reactjs 第一次加载页面时,React useEffect返回空数据数组

oxf4rvwz  于 2022-11-22  发布在  React
关注(0)|答案(2)|浏览(441)

我正在从useEffect对firebase进行API调用,当页面第一次加载时,返回的数据是空的,但如果我对代码进行任何更改并保存它,则会填充数据。我希望数据在页面第一次加载时出现。

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;

我尝试过将产品添加为useEffect依赖项,但它会创建一个无限循环获取。
在第一次页面加载时,我需要做什么来获取数据?

ddrv8njm

ddrv8njm1#

如果setProducts()之后的console.log(products)返回undefined,这是正常的,因为setProducts()是异步的,并且在记录日志时products尚未更新。
添加products作为依赖项将创建无限循环,因为同一个useEffect同时设置和侦听products
但是,如果您愿意,可以将筛选器的逻辑分离到第二个useEffect,并添加products作为其依赖项,因为筛选器实际上依赖于products
示例:
第一个

to94eoyn

to94eoyn2#

setState in react是异步的。在这里阅读更多。所以当你设置你的状态(产品)时,它需要一些时间来实际更新你的状态。
为了解决您的问题,您有两个选择。
首先是在products状态上编写另一个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]);

另一种方法是使用async/await,将产品存储在一个temp变量中,并使用该变量而不是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();
  }, []);

如果函数不是异步的,也可以删除async/await。

相关问题