[英]React useEffect is returning empty data array when page loads for the first time
I am making an API call to firebase from useEffect and the data returned is empty when the page loads for the first time but gets populated if I make any changes to the code and save it.我正在从 useEffect 对 firebase 进行 API 调用,当页面第一次加载时返回的数据为空,但如果我对代码进行任何更改并保存它就会填充。 I want the data to be present when the page loads for the first time.我希望数据在页面第一次加载时出现。
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { motion } from "framer-motion";
import { getDatabase, ref, onValue } from "firebase/database";
import Helmet from "../components/Helmet/Helmet";
import "../styles/home.css";
import { Container, Row, Col } from "reactstrap";
import heroImg from "../assets/images/hero-img.png";
import Services from "../services/Services";
import ProductsList from "../components/UI/ProductsList";
import Clock from "../components/UI/Clock";
import counterImg from "../assets/images/counter-timer-img.png";
const Home = () => {
const [isLoading, setIsLoading] = useState(true);
const [products, setProducts] = useState([]);
const [trendingProducts, setTrendingProducts] = useState([]);
const [bestSalesProducts, setBestSalesProducts] = useState([]);
const [mobileProducts, setMobileProducts] = useState([]);
const [wirelessProducts, setWirelessProducts] = useState([]);
const [popularProducts, setPopularProducts] = useState([]);
const year = new Date().getFullYear();
useEffect(() => {
const fetchProducts = () => {
const db = getDatabase();
const thumbnailRef = ref(db, "Contents/");
onValue(thumbnailRef, (snapshot) => {
const data = snapshot.val();
if (data !== null) {
Object.values(data).map((product) => {
return setProducts((oldArray) => [...oldArray, product]);
});
console.log(products);
}
});
};
const filteredTrendingProducts = products.filter(
(item) => item.category === "Kids"
);
const filteredBestSalesProducts = products.filter(
(item) => item.category === "Entertainment"
);
const filteredMobileProducts = products.filter(
(item) => item.category === "LifeStyle"
);
const filteredWirelessProducts = products.filter(
(item) => item.category === "wireless"
);
const filteredPopularProducts = products.filter(
(item) => item.category === "watch"
);
setTrendingProducts(filteredTrendingProducts);
setBestSalesProducts(filteredBestSalesProducts);
setMobileProducts(filteredMobileProducts);
setWirelessProducts(filteredWirelessProducts);
setPopularProducts(filteredPopularProducts);
setIsLoading(false);
fetchProducts();
}, []);
if (isLoading) {
return <div> Loading ... </div>;
}
return (
whileTap={{ scale: 1.2 }}
className="buy__btn store__btn"
>
<Link to="/shop">Visit Store</Link>
</motion.button>
</Col>
<Col lg="6" md="12" className="text-end counter__img">
<img src={counterImg} alt="" />
</Col>
</Row>
</Container>
</section>
<section className="new__arrivals">
<Container>
<Row>
<Col lg="12" className="text-center mb-5">
<h2 className="section__title">New Arrivals</h2>
</Col>
<ProductsList data={mobileProducts} />
<ProductsList data={wirelessProducts} />
</Row>
</Container>
</section>
<section className="popular_category">
<Container>
<Row>
<Col lg="12" className="text-center mb-5">
<h2 className="section__title">Popular in Category</h2>
</Col>
<ProductsList data={popularProducts} />
</Row>
</Container>
</section>
</Helmet>
);
};
export default Home;
I have tried adding products as the useEffect depencies but it creates an infinite loop fetching.我尝试将产品添加为 useEffect 依赖项,但它会创建无限循环获取。
What do I have to do for the data to be fetched on the first page load?我需要做什么才能在第一页加载时获取数据?
It is normal if console.log(products)
right after setProducts()
returns undefined
because setProducts()
is asynchronous and products
is not updated yet when logged.如果console.log(products)
在setProducts()
之后立即返回undefined
是正常的,因为setProducts()
是异步的并且记录时products
尚未更新。
Adding products
as a dependency will create a infinite loop because the same useEffect
is both setting and listening to products
.将products
添加为依赖项将创建一个无限循环,因为同一个useEffect
既设置又监听products
。
However if you prefer, you could separate the logic for filters to a second useEffect
and add products
as its dependency, since the filtered are actually dependent on products
.但是,如果您愿意,您可以将过滤器的逻辑分离到第二个useEffect
并将products
添加为其依赖项,因为过滤实际上依赖于products
。
Example:例子:
useEffect(() => {
const fetchProducts = () => {
const db = getDatabase();
const thumbnailRef = ref(db, "Contents/");
onValue(thumbnailRef, (snapshot) => {
const data = snapshot.val();
if (data !== null) {
Object.values(data).map((product) => {
return setProducts((oldArray) => [...oldArray, product]);
});
console.log(products);
}
});
};
setIsLoading(false);
fetchProducts();
}, []);
useEffect(() => {
const filteredTrendingProducts = products.filter(
(item) => item.category === "Kids"
);
const filteredBestSalesProducts = products.filter(
(item) => item.category === "Entertainment"
);
const filteredMobileProducts = products.filter(
(item) => item.category === "LifeStyle"
);
const filteredWirelessProducts = products.filter(
(item) => item.category === "wireless"
);
const filteredPopularProducts = products.filter(
(item) => item.category === "watch"
);
setTrendingProducts(filteredTrendingProducts);
setBestSalesProducts(filteredBestSalesProducts);
setMobileProducts(filteredMobileProducts);
setWirelessProducts(filteredWirelessProducts);
setPopularProducts(filteredPopularProducts);
}, [products]);
setState in react is async. react 中的 setState 是异步的。 Read more here . 在这里阅读更多。 So when you set your state (products), it takes some time to actually update your state.因此,当您设置 state(产品)时,实际更新您的 state 需要一些时间。
In order to fix your problem, you have 2 options.为了解决您的问题,您有两种选择。
First is to write another useEffect on your products state and move your logic there like this:首先是在您的产品 state 上编写另一个 useEffect 并将您的逻辑移动到那里,如下所示:
useEffect(() => {
const fetchProducts = () => {
const db = getDatabase();
const thumbnailRef = ref(db, "Contents/");
onValue(thumbnailRef, (snapshot) => {
const data = snapshot.val();
if (data !== null) {
Object.values(data).map((product) => {
return setProducts((oldArray) => [...oldArray, product]);
});
console.log(products);
}
});
};
fetchProducts();
}, []);
useEffect(() => {
const filteredTrendingProducts = products.filter(
(item) => item.category === "Kids"
);
const filteredBestSalesProducts = products.filter(
(item) => item.category === "Entertainment"
);
const filteredMobileProducts = products.filter(
(item) => item.category === "LifeStyle"
);
const filteredWirelessProducts = products.filter(
(item) => item.category === "wireless"
);
const filteredPopularProducts = products.filter(
(item) => item.category === "watch"
);
setTrendingProducts(filteredTrendingProducts);
setBestSalesProducts(filteredBestSalesProducts);
setMobileProducts(filteredMobileProducts);
setWirelessProducts(filteredWirelessProducts);
setPopularProducts(filteredPopularProducts);
setIsLoading(false);
}, [procuts]);
And the other way is to use async/await and store your products in a temp variable and use the variable instead of the state:另一种方法是使用异步/等待并将您的产品存储在临时变量中并使用该变量而不是 state:
useEffect(async () => {
let tempProducts = [];
const fetchProducts = async () => {
const db = await getDatabase();
const thumbnailRef = await ref(db, "Contents/");
await onValue(thumbnailRef, (snapshot) => {
const data = snapshot.val();
if (data !== null) {
Object.values(data).map((product) => {
tempProducts = [...products, product]
return setProducts(tempProducts);
});
console.log(tempProducts);
}
});
};
const filteredTrendingProducts = tempProducts.filter(
(item) => item.category === "Kids"
);
const filteredBestSalesProducts = tempProducts.filter(
(item) => item.category === "Entertainment"
);
const filteredMobileProducts = tempProducts.filter(
(item) => item.category === "LifeStyle"
);
const filteredWirelessProducts = tempProducts.filter(
(item) => item.category === "wireless"
);
const filteredPopularProducts = tempProducts.filter(
(item) => item.category === "watch"
);
setTrendingProducts(filteredTrendingProducts);
setBestSalesProducts(filteredBestSalesProducts);
setMobileProducts(filteredMobileProducts);
setWirelessProducts(filteredWirelessProducts);
setPopularProducts(filteredPopularProducts);
setIsLoading(false);
await fetchProducts();
}, []);
You can also delete async/await if the functions are not async.如果函数不是异步的,您也可以删除 async/await。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.