Image Picker - save uri with Hook - reactjs

I have a little problem with saving my uri of a picture I have chosen in my react native app.
The following code sample is crucial:
const ProfileScreen = props =>{
const [pickedImage, setPickedImage] = useState(null);
const [modalVisible, setModalVisible] = useState(false); //State for visible Modal
const [userBio, setUserBio] = useState('Useless Placeholder'); //State for users text in the bio
const verifyPermissions = async () => { //ask for permissions on iOS and Android
const result = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (result.status !== 'granted'){
Alert.alert("Insufficient permissions!", "You need to grant galery permissions to customise your profile picture!", [{text: "Got it."}]);
return false;
};
return true;
};
const takeImageHandler = async () => { //function that opens up the camera
const hasPermission = await verifyPermissions();
if (!hasPermission){
return;
}
const image = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
quality: 0.5,
aspect: [16,16]
});
setPickedImage(image.uri);
console.log("Data raw is: " + image.uri);
console.log("Data from hook is: " + pickedImage);
};
if(userBio.length == 0 && modalVisible == false){
setUserBio("Useless Placeholder");
};
As you can see, I have 2 console logs to check my outcome. I want to save the image.uri to my hook I declared at the top of my ProfileScreen. The problem is what I get as an output in my console:
Data raw is:
file:/data/user/0/host.exp.exponent/cache/ExperienceData/%2540kubaguette%252FPigeonBuddy/ImagePicker/30953995-840b-451e-a505-6082df16b9e3.jpg
Data from hook is: null
Why is setPickedImage(image.uri) not working here? Why can I console.log my uri of the chosen picture but not save this uri to my hook and retrieve it?

setPickedImage as any method which updates the state is async by nature.
If this is the only issue, you can track the changes with useEffect.
useEffect(() => {
console.log(pickedImage);
}, [pickedImage]);
You can see the difference here: https://codesandbox.io/s/usestate-async-rnzox?file=/src/App.js

Related

How can I avoid the infinite loop in useEffect when using a function that is wrapped in useCallback?

I have this function that fetches user's info from FireBase and saves it to useState:
const [fireBaseUser, setfireBaseUser] = useState('');
const getUserData1 = useCallback(async(uid) => {
const userRef = doc(db, "users", uid);
const docSnap = await getDoc(userRef); // not getDocs
console.log(docSnap.data());
if(docSnap.data()) {
setfireBaseUser(docSnap.data());
} else {
return false; // .data() if undefined is doc doesn't exist
}
}, [fireBaseUser]);
and this function gets run each time there is a change to a state called 'currentUser' which
is tied to Firebase's onAuthStateChanged function which provies the latest instance of user's authentication state. After successful authentication, dBCtx.getUserData1 function
gets called and brings in other user information from FireStore which saves these user information to 'fireBaseUser' state.
in useEffect like below:
const [currentUser, setCurrentUser] = useState('');
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
setCurrentUser(user);
console.log('currentuser:');
console.log(user.uid);
dBCtx.getUserData1(user.uid)
.then((result)=>{
if(result === false) {
console.log('creating a user profile for' + user.uid)
dBCtx.createUser(user.displayName, user.email, user.uid);
}
});
// ...
} else {
console.log('not logged in')
}
});
}, [currentUser])
I have another useEffect that works just below that listens in on 'fireBaseUser' state changes to update changes whenever the user makes changes to their profile.
useEffect(() => {
console.log('firebase User');
console.log(dBCtx.fireBaseUser);
getUserData1(dBCtx.fireBaseUser.uid);
}, [dBCtx.fireBaseUser])
For example:
if a user decides to change his name:
async function updateName(newName) {
const userRef = doc(db, "users", fireBaseUser.uid);
await updateDoc(userRef, {
displayName: newName
});
const docSnap = await getDoc(userRef);
setfireBaseUser(prevState => {
return {displayName: docSnap.displayName,
...prevState}
});}
But at the moment, as soon as my app.js starts up, the app/react goes into an infinite loop.
because of this code below in the second useEffect as I have described.
So the question is...
How can I update changes to useEffect withouth ending up in infinite loop???
Please let me know!

react page doesnt render when getting the data back from server

react won't work when rendering the page, but when i changed code in the vscode (added a line of console or comment one line out), the page is rendered. or when page is not rendered. when i hit refresh. i can see some of my content but it won't render. the usestate doesnt seem like to successfully save the value
const ParkDetail = () => {
const [parkId, setParkId] = useState('')
const [park, setpark] = useState('')
const [areas, setAreas] = useState([])
const [ridesName, setridesName] = useState([])
const [rides, setrides] = useState([])
let { id } = useParams()
console.log(id)
useEffect(() => {
async function getPark() {
try {
await setParkId(id)
const res = await axios.get(`/parks/details/${parkId}`)
console.log(res)
const park1 = await res.data.park
console.log(park1)
await setpark(park1)
console.log(park)
await setAreas(park1.serviceAnimalRelief)
// await setridesName(park1.topRides)
// console.log(ridesName)
} catch (e) {
console.log(e.message)
}
}
getPark()
}, [parkId])
}
I believe the problem is you using the state as parameters in your get requests. Since state setter functions do not return promises, using await on them is basically of no use. You should rather use the variables that you obtain from the get requests directly. For example, use id instead of parkId and so on.

use async await in handleSubmit react redux-toolkit

I have a final form in a react page that i need to show me a global success if all the data have been sotored in their database.
I have two partial forms (variations and generalInfo) that store the data in two tables in sql.
I use this handlesubmit from last step in the form to store this data.
const handleSubmit = (e) => {
e.preventDefault();
dispatch(setDesignResponse(dataResponse));
dispatch(createNewVariations(variations));
dispatch(createNewJsonResponse(newJsonResponse));
};
i have my slices that return me info if the store is succesfully.
export const createNewJsonResponse = createAsyncThunk (
"new-json-response/post",
async (newData) => {
const { accesToken, newDataResponse } = newData;
const res = await FaqsService.createNewResponse(newDataResponse, accesToken);
return res.data;
}
);
export const createNewVariations = createAsyncThunk (
"new-variations/post",
async (variations) => {
try {
console.log(variations);
const { token, variationsData } = variations;
const res = await FaqsService.createNewVariations(variationsData, token);
console.log(res.data);
alert('VARIACIONES CREADAS PERFECTAMENTE');
return res.data;
} catch(error) { console.log(error);}
}
);
If just i have one call to one api i know how to show and alert to inform the user. Like in the above code (createNewVariations).
But i need to check if both are ok, and then show the alert to the user.
I think that i can do something in the component, in the handlesubmit, to send the info to the slices, store the data in the data bases, return de result succesfuly (with an state that return a true or false from slices (with extrarducer like:
extraReducers: {
[createNewJsonResponse.fulfilled]:(state, action) => {
state.isCreated = action.payload.message; // initial state is: isCreated:false
}
}
// (the same for the other slice).
),
and then pop-up the alert.
Is it possible?
thanks
Yes you can have isCreated in both of the state slices and then have if condition on your compoment which show success alert when both of the isCreated Flag is 1
I have create a Github example for this I am using a counter example,
from # Redux + Plain JS template
npx create-react-app my-app --template redux
and modified the code to demo that how you can achieve it.
You would need to look on the src/feature/counter/Counter.js File
There I have below logic, this is the not full code of the component, you can look that in the Github repo. and yes you can have isCreated on multiple slices and have if condition on the component, that will work for which you are looking for.
export function Counter() {
const count = useSelector(selectCount);
const incrementStatus = useSelector(incrementCountStatus);
const incrementStatusNew = useSelector(incrementCountStatusNew);
const dispatch = useDispatch();
const [incrementAmount, setIncrementAmount] = useState('2');
console.log(`Increment Status:`, incrementStatus);
console.log(`Increment Status New:`, incrementStatusNew);
const incrementValue = Number(incrementAmount) || 0;
const handleAsyncSubmit = () => {
dispatch(incrementByAmount(incrementValue))
dispatch(incrementAsyncNew(incrementValue))
}
if (incrementStatus === 'success' && incrementStatusNew === 'success') {
alert('Data have been saved successfully.');
}
GitHub Repo

Can't have my data from firebase after get method with reactjs

Hello i take data from realtime database in firebase with this way.
useEffect(() => {
async function asyncCall() {
const myurl = await axios.get("https://mysiteproject- 8adcf.firebaseio.com/products.json")
setUrl(myurl)
}
asyncCall();
},[]);
The result of when i
console.log(url)
showing in the below image
When i
console.log(url.data)
this is shown up
That is the data i want to map. But when i
console.log(url.data.id)
this is shown up in my console
Can anyone tell me why this happening.
Also i try this in my code
useEffect(() => {
async function asyncCall() {
const myurl = await axios.get("https://mysiteproject-8adcf.firebaseio.com/products.json")
setUrl(myurl)
}
asyncCall();
},[]);
let myvar = url.data;
console.log(myvar);
{myvar.map((myvar => (
console.log(myvar.id)
)))}
But again i have a error
Can anyone help me with this??
You should add check if url.data is exists. When you render console.log(myvar); - url.data is undefined because you didn't get it from the server yet. So your code should looks like this:
useEffect(() => {
async function asyncCall() {
const myurl = await axios.get(
"https://mysiteproject-8adcf.firebaseio.com/products.json"
);
setUrl(myurl);
}
asyncCall();
}, []);
if (url.data) {
let myvar = url.data;
console.log(myvar);
myvar.map((myvar) => console.log(myvar.id));
}
When you'll get url.data the component will be updated because you update state via setUrl and the data will be logged to console.

How to upload image to Firebase during sign up?

I am trying to upload an image to Firebase storage. The problem is that since the user has not signed up yet, I don't have their uid.
I depend on onAuthStateChanged to get the user id and upload an image to their bucket, but so far it hasn't turned out well.
const { userObject } = useContext(Context) //trying to get the uid from here
onSubmit={(values, { setSubmitting }) => {
async function writeToFirebase() {
firebaseService.auth.createUserWithEmailAndPassword(values.email, values.password)
await firebaseService.firestore.collection('businessesPendingAdminApproval').add(values)
}
writeToFirebase()
async function sendToFirebaseImageBucket(photo, uid) {
const businessRef = await firebaseService.firestore.doc(
`businessesPendingAdminApproval/${uid}`,
)
firebaseService.storage
.ref()
.child('businesses')
.child(uid)
.child('avatar-image')
.put(photo)
.then(response => response.ref.getDownloadURL())
.then(photoURL => businessRef.update({ avatarImage: photoURL })) //try to update avatarImage
}
const uid = userObject.uid //undefined, can't get uid
sendToFirebaseImageBucket(values.avatarImage, uid) //uid gets passed as undefined
}}>
The way I am setting the userObject which is where I'm trying to get the uid from.
Setting the userObject eventually works but maybe not fast enought for me to be able to pass it to a function (as in the code above).
useEffect(() => {
firebaseService.auth.onAuthStateChanged(async function (userAuth) {
if (userAuth) {
const user = await firebaseService.createUserProfileDocument(userAuth)
setUserObject(user) //set userObject which has an uid field.
} else {
console.log('no one signed in')
}
})
}, [])
Just add your image to cloud storage right after you have logged in and was able to get uid. the following code can help you, it works for me as well. put the following code inside useEffect.
const unsubscribe = auth().onAuthStateChanged(user => {
if (user.uid){
const ref = storage.ref(`images/${user.uid}`);
const task = ref.putFile(_image, { contentType: 'image/jpeg' });
task.on(firebase.storage.TaskEvent.STATE_CHANGED, snap => {
setState({ type: 'cents', value: snap.bytesTransferred / snap.totalBytes * 100 });
}, err => { console.log('Error in help:persisAppState: ', err) }, async () => {
const image = await ref.getDownloadURL();
if (image) await db.collection("imagelinks").doc(user.id).set({ image });
});
}
});

Resources