繁体   English   中英

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

[英]React useEffect is returning empty data array when page loads for the first time

我正在从 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 依赖项,但它会创建无限循环获取。

我需要做什么才能在第一页加载时获取数据?

如果console.log(products)setProducts()之后立即返回undefined是正常的,因为setProducts()是异步的并且记录时products尚未更新。

products添加为依赖项将创建一个无限循环,因为同一个useEffect既设置又监听products

但是,如果您愿意,您可以将过滤器的逻辑分离到第二个useEffect并将products添加为其依赖项,因为过滤实际上依赖于products

例子:

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]);

react 中的 setState 是异步的。 在这里阅读更多。 因此,当您设置 state(产品)时,实际更新您的 state 需要一些时间。

为了解决您的问题,您有两种选择。

首先是在您的产品 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]);

另一种方法是使用异步/等待并将您的产品存储在临时变量中并使用该变量而不是 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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM