Reputation: 304
In my application, for some reason, data for the Home page is loaded only after going to another page and then returning to the Home page.
This is most likely due to the fact that the data from the firestore
is rendered for several seconds, and the data is transmitted to the home page as an empty array.
I understand that this is something like this, but how to solve this problem I can not find a solution.
Also, if you see any obvious errors in my code, please tell me, since I just started learning React and can still make some stupid mistakes
Menu
function Menu() {
const [data, setData] = useState([]);
const { user } = UserAuth();
const fetchProduct = async () => {
const querySnapshot = await getDocs(collection(db, "langcards-db"));
const arr = [];
querySnapshot.forEach((doc) => {
arr.push({
...doc.data(),
id: doc.id,
});
});
setData(arr);
}
useEffect(() => {
if(user){
fetchProduct();
}else{
setData([])
}
}, []);
useEffect(() => {
if(user){
fetchProduct();
}else{
setData([])
}
}, [user]);
return (
<div className="content">
<Routes>
<Route
path="/"
element={<Layout onSearch={() => onSearchF()} data={data} />}
>
<Route index element={<Home data={data} num={data.length} />}/>
<Route
path="saved"
element={<Saved data={data} setData={setData} />}
/>
</Route>
</Routes>
</div>
);
}
export default Menu;
Home
const shuffle = (arr) => arr.sort(() => Math.random() - 0.5);
function Home({ data, num }) {
const [newArr, setNewArr] = useState(shuffle([...data]));
const [i, setI] = useState(0);
const randomCard = useMemo(() => {
if (!newArr || i < 0 || i >= newArr.length) return undefined;
return newArr[i];
}, [newArr, i]);
const randomizeCard = () => {
if (i < newArr.length - 1) {
setI(i + 1);
} else {
setNewArr(shuffle([...data]));
setI(0);
}
};
return (
<div>
<div className="home-inner">
{num >= 1 && randomCard ? (
<div className="home-stat">
<p className='saved-stat'>
Saved words: <span>{num}</span>
</p>
<div onClick={randomizeCard} className="home-random">
<div className="hr-card">
<p className="randomword">{randomCard.word}</p>
<p className="randomtranslate">{randomCard.translate}</p>
</div>
</div>
<Link className="home-btn main-btn" to="/saved">
See all
</Link>
</div>
) : (
<div>
{" "}
<div className="oops-section">
<Link className="main-btn" to="/addcard">
Add first word
</Link>
</div>
</div>
)}
</div>
</div>
);
}
Upvotes: 0
Views: 42
Reputation: 753
You can use a state to check when your fetch is finished and show your data only then. See below
function Menu() {
const [data, setData] = useState([]);
const { user } = UserAuth();
const [isLoading, setIsLoading] = useState(true); // Added state
const fetchProduct = async () => {
const querySnapshot = await getDocs(collection(db, "langcards-db"));
const arr = [];
querySnapshot.forEach((doc) => {
arr.push({
...doc.data(),
id: doc.id,
});
});
setData(arr);
setLoading(false);
}
/* useEffect(() => { ---> this code this redundant and can be removed
if(user){
fetchProduct();
}else{
setData([])
}
}, []);*/
useEffect(() => {
if(user){
fetchProduct();
}else{
setData([])
}
}, [user]);
const HomeRoute = () => isLoading ? <div>Loading...</div> : <Home data={data} num={data.length} /> // Conditional rendering
return (
<div className="content">
<Routes>
<Route
path="/"
element={<Layout onSearch={() => onSearchF()} data={data} />}
>
<Route index element={<HomeRoute/>}/>
<Route
path="saved"
element={<Saved data={data} setData={setData} />}
/>
</Route>
</Routes>
</div>
);
}
export default Menu;
Upvotes: 1