I have created a simple react app using functional components. The parent component is 'Sites' while the child is 'View Sites'. I have this function in my parent (Sites component)
function getSitesDB() {
ref.onSnapshot((querySnapshot) => {
const items = [];
querySnapshot.forEach((doc) => {
items.push(doc.data());
});
return items;
});
}
I want to call this function from my child (view sites) component and get the return value to it. for that I have rendered my child component as this,
<Route exact path="/sites">
<ViewSites getSitesDB={getSitesDB}></ViewSites>
</Route>
And called the function using props from the child component as this,
useEffect(() => {
setLoading(true);
const returnVal = props.getSitesDB();
setLoading(false);
}, []);
I get this returnVal variable as undefined, but this function calls the parent function properly. Just want to know how to get the return value back. Please help me as I'm new to react.
CodePudding user response:
currently, you are not returning anything from the getSitesDB()
function, and you can't because you only get access to querySnapshot
when the callback is called, you can try returning a promise
from getSitesDB()
and resolve it with items
when the callback is called, something like this:
function getSitesDB() {
return new Promise((resolve, reject)=> {
ref.onSnapshot((querySnapshot) => {
const items = [];
querySnapshot.forEach((doc) => {
items.push(doc.data());
});
resolve(items);
});
})
}
and then in your useEffect()
, chain a .then()
to the function like this,
useEffect(() => {
setLoading(true);
props.getSitesDB().then(returnVal => {
// set returnVal to some state here so you can use it somewhere else in your component
// =>> setState(returnVal)
setLoading(false);
})
}, []);
I am not sure if it will work fine, because I don't know where that 'onSnapshot' comes from, it looks like it listens for an event and calls the callback each time(may be more than once) some change happens, in that case it might throw an error as promise would've already be resolved on initial call.
read more on promises here at mdn
CodePudding user response:
When calling the getSitesDB
you should return the items that you got from firestore's onSnapshot
function. the onSnapshot
function ignores your return items...
To fetch the data you should do something like this:
function getSitesDB() {
return new Promise((resolve, reject) => {
const items = [];
ref.onSnapshot((querySnapshot) => {
querySnapshot.forEach((doc) => items.push(doc.data()));
resolve(items);
});
});
}
To support unmount on your useEffect
you should do something like this:
useEffect(() => {
let canceled = false;
const fetchData = async () => {
setLoading(true);
const sitesData = await getSitesDB();
if (!canceled) {
setSitesData(sitesData);
setLoading(false);
}
}
fetchData();
return () => {
canceled = true;
}
}, [getSitesDB]);
CodePudding user response:
You can achive with many ways. 1 Redux 2 Context API 3 Traditional way (Pass that function as props in Parent Component)
When ever you get function as a props in component You can use like below mention way
useEffect(() => { const returnValue = props.funtionMentionInParent(); console.log(returnValue) }, []);
Thank you
CodePudding user response:
In Parent use state to keep the result of function
import React, { useState } from "react";
const [sitesDB, setSitesDB] = useState(null);
Also use setSitesDB(items)
to update the value in the state.
function getSitesDB() {
ref.onSnapshot((querySnapshot) => {
const items = [];
querySnapshot.forEach((doc) => {
items.push(doc.data());
});
setSitesDB(items); // here state is updated
return items;
});
}
Then pass the function and the state to the Child
<Route exact path="/sites">
<ViewSites getSitesDB={getSitesDB} sitesDB={sitesDB}></ViewSites>
</Route>
Call the function in Child. And use state sitesDB
where you need.
useEffect(() => {
setLoading(true);
props.getSitesDB();
setLoading(false);
}, []);
console.log(props.sitesDB);