I'm trying to push a new screen to display the selected item's detail, when I get the data it fetches the document correctly, however if I try to set my object to use it in my screen it is undefined, but if I reload the app it does populate the object, here's the code:
const [event, setEvent] = useState();
const getEvent = async (dbx) => {
const eventDoc = doc(dbx, 'events', eventId);
try {
const eventSnapshot = await getDoc(eventDoc);
if(eventSnapshot.exists()) {
const fetchedEvent = eventSnapshot.data();
setEvent(fetchedEvent);
} else {
console.log("Document does not exist")
}
} catch(error) {
console.log(error)
}
return;
}
useEffect(
()=>{
getEvent(db)
console.log("Event Here: ", event);
}
,[])
Setting a variable in the state is an asynchronous operation. In fact, so is loading data from Firestore, so neither of those operations is done by the time your console.log("Event Here: ", event) runs.
If you want to log the event value, use another effect that depends on that state variable to do so:
useEffect(()=>{
console.log("Event Here: ", event);
},[event])
Related
fetchedAuthor is a author object. isFollow is his follower count. when someone clicks on folow isFollow changes. when isFollow changes i want to rerun useEffect. when the author changes, the fetchedAuthor changes but i dont want this useEffect to reRun as this is strictly for follower handling not author handling but at the same time when the author changes i want this useEfffect to know that author has changed so the next time when isFollow changes the useEffect doesnt fetch with the previous fetchedAuthor but the latest value of fetchedAuthor.
useEffect(() => {
setCurrentAuthor(fetchedAuthor) ;
},[fetchedAuthor]) ;
useEffect(async () => {
try {
const response = await fetch(`URL/${currentAuthor}/${isFollow}`);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}},[isFollow]) ;
would this help me to get the appropriate response ?
Use a ref to store the current fetchedAuthor. Update the ref whenever fetchedAuthor changes. Use the ref's value when calling the api:
const authorRef = useRef(fetchedAuthor);
useEffect(() => {
authorRef.current = fetchedAuthor;
}, [fetchedAuthor]);
useEffect(async() => {
try {
const response = await fetch(`URL/${authorRef.current}/${isFollow}`);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}, [isFollow]);
I am making a real-time chat app with react native and socket.io and trying to update the messages state array with new data whenever the 'chat message' event fires. But inside the callback function, the value of messages is always an empty array, however, the desired behavior is that it contains the list of previous messages and just pushes the new data in the array.
I can't figure out what's going on here. I think maybe it's because of the callback function's closure. I wanted to know what is the correct way to modify state variables from inside the event listeners?
const [messages, setMessages] = useState([]);
const _onMessage = (data) => {
console.log(`${client.id} : ${JSON.stringify(data)}`);
console.log('new message');
};
const connect_socket = () => {
client.connect();
client.on('connect', _onConnect);
client.on('disconnect', _onDisconnect);
client.on('chat message', (data) => {
console.log(`${client.id} : ${JSON.stringify(data)}`);
console.log('new message');
console.log(messages); // this is always empty despite it being the state variable
const temp = messages.slice();
console.log(temp);
temp.push(data);
console.log(temp);
setMessages(temp);
});
};
const remove_socket = () => {
client.disconnect();
// client.removeListener('connect', _onConnect);
// client.removeListener('disconnect', _onDisconnect);
// client.removeListener('chat message', _onMessage);
client.off('connect');
client.off('disconnect');
client.off('chat message');
};
I am attempting to push data into local storage in react native, in this case push multiple elements. I am attempting to use documentation pointed out here:
How do I set multiple values within Asyncstorage
How would I go about doing this properly? Below is some code:
What I am currently doing
const STORAGE_KEY = '#save_enableauto';
const DBLTIME_KEY = '#save_dbltime';
state={
times: Times,
messageTimes: {
dblTime: '12:00 pm',
genTime: '12:00 pm'
}
enableAuto:false
}
//retrieves automatic messaging status
_retrieveData = async () => {
try {
//pull data from local storage
const enableAuto = await AsyncStorage.getItem(STORAGE_KEY);
const dblTime = await AsyncStorage.getItem(DBLTIME_KEY);
console.log('auto messages set: ',enableAuto);
console.log('time data is:', dblTime);
//reset state for time if it exists in local storage
if(dblTime !==null) {
this.setState(prevState => ({
messageTimes: { // object that we want to update
...prevState.messageTimes, // keep all other key-value pairs
dblTime: dblTime // update the value of specific key
}
}))
}
//reset state for notifications if exists in local storage
if (enableAuto !== null) {
// We have data!!
console.log('receiving from local storage: ',enableAuto);
this.setState({ enableAuto:eval(enableAuto) });
}
} catch (error) {
alert('failed to load previous settings.')
// Error retrieving data
}
};
//trying to set it up with one call
_retrieveDataGroup = async () => {
const items = JSON.stringify([['k1', STORAGE_KEY], ['k2', DBLTIME_KEY]]);
try {
const localData = AsyncStorage.multiGet(items, () => {
//to do something
});
console.log('Group fetch: ',localData);
} catch (error) {
alert('failed to load previous settings.')
// Error retrieving data
}
};
right now what I receive when console logging group fetching is a promise:
Group fetch: Promise {
"_40": 0,
"_55": null,
"_65": 0,
"_72": null,
}
multiGet is a Promise. Add await before calling it.
const localData = await AsyncStorage.multiGet(items, () => {
//to do something
});
I want to send a notification to a specific device so I write this function and its work right but I got undefined in the username
Logs output:
Get this
after: { '-LhjfwZeu0Ryr6jYRq5r': { Price: '888', date: '2019-6-19', description: 'Ghh', id: 50, nameOfProblem: 'Vbh', providerName: 'Loy', providerService: 'Carpenter', statusInfo: 'Incomplete', time: '15:22', username:"devas" }}
And the username is undefined
Here is the function
exports.sendPushR = functions.database.ref('/request/{pid}/{uid}/orders')
.onWrite(async (snapshot, context) => {
const registrationTokens = "------";
const providerId = context.params.pid;
const userId = context.params.uid;
const event = context.params;
console.log("event", event);
console.log(`New Order from ${userId} to ${providerId}`);
const afterData = snapshot.after.val(); // data after the write
const username = snapshot.after.val().username;
console.log(afterData);
console.log(username);
const payload = {
notification: {
title: 'Message received',
body: `You received a new order from ${username} check it now! `,
sound: "default",
icon: "default",
}
};
try {
const response = await admin.messaging().sendToDevice(registrationTokens, payload);
console.log('Successfully sent message:', response);
}
catch (error) {
console.log('Error sending message:', error);
}
return null;
});
It looks like the code you wrote is meant to run when a new order is added to the database. But you've declared it to trigger like this:
exports.sendPushR = functions.database.ref('/request/{pid}/{uid}/orders')
.onWrite(async (snapshot, context) => {
This means that the code instead triggers whenever anything is written under the orders node for a user. To trigger only when an order is written under that orders node, define your trigger as:
exports.sendPushR = functions.database.ref('/request/{pid}/{uid}/orders/{orderid}')
.onWrite(async (snapshot, context) => {
The difference above is that the path now includes {orderid} meaning that it triggers one level lower in the tree, and your snapshot.after will no longer contain the -L level.
Since you actually only seem to care about when an order gets created, you can also only trigger on that (meaning your function won't get called when an order gets updated or deleted). That'd be something like this:
exports.sendPushR = functions.database.ref('/request/{pid}/{uid}/orders/{orderid}')
.onCreate(async (snapshot, context) => {
...
const afterData = snapshot.val();
const username = snapshot.val().username;
console.log(afterData);
console.log(username);
...
});
Here we again trigger on the lower-level in the JSON. But since we now trigger onCreate, we no longer have a before and after snapshot, and instead just do snapshot.val() to get the data that was just created.
Since the object you are retrieving has a generated member you could use a for-in loop to retrieve the value.
const object = snapshot.after.val()
for(const key in object) {
if (object.hasOwnProperty(key)) {
const element = object[key];
if(element.username) {
console.log(element.username);
break;
}
}
}
I am succesfully updating my user's profile picture on their profile and on all of their reviews posted with this function:
export const storeUserProfileImage = (url) => {
const { currentUser } = firebase.auth();
firebase.database().ref(`/users/${currentUser.uid}/profilePic`)
.update({ url });
firebase.database().ref('reviews')
.orderByChild('username')
.equalTo('User3')
.once('value', (snapshot) => {
snapshot.forEach((child) => {
child.ref.update({ profilePic: url });
});
});
};
I am aware that I should be using an atomic update to do this so the data updates at the same time (in case a user leaves the app or something else goes wrong). I am confused on how I can accomplish this when querying over child values.
Any help or guidance would be greatly appreciated!
Declare a variable to store all the updates. Add the updates as you read them on your listener's loop. When the loop is finished, run the atomic update.
export const storeUserProfileImage = (url) => {
const { currentUser } = firebase.auth();
firebase.database().ref('reviews')
.orderByChild('username')
.equalTo('User3')
.once('value', (snapshot) => {
var updates = {};
updates[`/users/${currentUser.uid}/profilePic`] = url;
snapshot.forEach((child) => {
updates[`/reviews/${child.key}/profilePic`] = url;
});
firebase.database().ref().update(updates);
});
};