简体   繁体   English

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

[英]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.

相关问题 第一次加载页面时,React useEffect 返回空数据 - React useEffect is returning empty data when page loads for the first time 首次加载页面时未定义 firebase 和 nextjs 的 useEffect - useEffect with firebase and nextjs undefined when page first loads Firestore 查询在页面首次加载时没有得到结果,但在页面重新呈现时 - React Native - Firestore query not getting results when page first loads, but is when page re-renders - React Native 为什么在存在子集合时从 Firestore 检索的数据返回空数组? - Why is data retrieved from Firestore returning empty array when there are subcollections present? Firebase 实时数据库在 React Native 中返回一个空数组 - Firebase realtime database returning an empty array in React Native React-Firebase:为什么页面在第一次加载时失败,但在刷新时加载正确? - React-Firebase: Why does page fail on first load, but then loads properly on refresh? React 和 Firebase Firestore V9 上一页分页返回“第一页” - React and Firebase Firestore V9 Previous Page Pagination returning to "first page" 为什么recyclerview数据只有在第二次点击按钮时才加载 - Why does the recyclerview data loads only when the button is clicked the second time 首次使用 navigation.navigate 加载页面时未获取 currentUser.uid - Not getting currentUser.uid when the page first loads using navigation.navigate Promise 存在数据时从 Firestore 返回空值 - Promise returning empty value from Firestore when data is present
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM