首页 > 解决方案 > 状态为空,在 useEffect 挂钩之后

问题描述

我正在尝试通过在 useEffect 中调度方法来设置产品。但是,状态仍然显示为空。

索引.html

import React, { useEffect, Fragment } from "react";
import { useSelector, useDispatch } from "react-redux";

import { fetchProductsData } from "../../store/products-actions";

import Promotion from "./components/Promotion";
import Products from "./components/Products";
import ToastUi from "../../shared/ui/ToastUi";

import { Container, Row, Col } from "react-bootstrap";

const Home = () => {
  const dispatch = useDispatch();

  // const products = useSelector((state) => state.products.products);
  const products = useSelector((state) => state.products.productsTest);
  const cartQuantity = useSelector((state) => state.cart.quantity);

  useEffect(() => {
    dispatch(fetchProductsData());
  }, [dispatch]);

  return (
    <Fragment>
      <ToastUi
        status="Sukses"
        title="Notifikasi"
        message={`(${cartQuantity}) produk baru berhasil di masukkan keranjang`}
      />
      <Container fluid="xl">
        <Row>
          <Col>
            <Promotion />
          </Col>
        </Row>
        <Row className="mt-3" md={3}>
          <Products products={products} />
        </Row>
      </Container>
    </Fragment>
  );
};

export default Home;

一个周期后产品仍然显示 null ,显然它需要第二个周期才能改变该状态。不知道我怎样才能让它在一个周期内改变。我是否需要将 useEffect 放在 parent 中?

编辑 如果我添加这个,它会起作用

 {products !== null && <Products products={products} />}
 // {/* <Products products={products} /> */} // 

但是,是否有更好的方法或解释为什么会发生这种情况,谢谢。

编辑

产品-slice.js

import { createSlice } from "@reduxjs/toolkit";

import {
  products,
  excel_products,
  product,
  filteredProducts,
  productsTest,
} from "../datafiles";

const initialProductsState = {
  products,
  excel_products,
  product,
  filteredProducts,
  productsTest,
};

const productsSlice = createSlice({
  name: "products",
  initialState: initialProductsState,
  reducers: {
    viewExcelProducts(state, action) {
      state.excel_products = action.payload;
    },
    uploadExcelProducts(state) {
      if (excel_products.length < 0) {
        console.log("error");
      } else {
        const newProducts = state.products.concat(state.excel_products);
        state.products = newProducts;
        state.excel_products = [];
      }
    },
    selectProduct(state, action) {
      const product = state.products.find((item) => item.id === action.payload);
      state.product = product;
    },
    filterProducts(state, action) {
      const filteredProducts = state.products.filter(
        (item) => item.type === action.payload
      );
      state.filteredProducts = filteredProducts;
    },
    setProducts(state, action) {
      state.productsTest = action.payload;
    },
  },
});

export const productsActions = productsSlice.actions;
export default productsSlice;

产品-actions.js

import { productsActions } from "./products-slice";

export const fetchProductsData = () => {
  return async (dispatch) => {
    const fetchData = async () => {
      const response = await fetch("http://localhost:5000/products");

      if (!response.ok) {
        throw new Error("Could not fetch data!");
      }
      const data = await response.json();

      return data;
    };
    try {
      const productsData = await fetchData();
      dispatch(productsActions.setProducts(productsData));
    } catch (err) {
      console.log("Error: " + err);
    }
  };
};

标签: javascriptreactjsreact-reduxreact-hooks

解决方案


你是什​​么意思it needs second cycle to make that state changed

fetchProductsData我假设是一个异步函数。这意味着您不会立即收到数据,而是在一段时间后(取决于网络连接速度、有效负载大小等)。因此,您的数据稍后到达是可以的。

异步数据的常用方法是保持isLoading您的状态。并按如下方式使用:

  const isLoading = useSelector((state) => state.products.isLoading);
  ...
  return (
    <Fragment>
      ...
      {isLoading && <Spinner />} // Some loading indicator
      {!isLoading && <Products products={products} />}
    </Fragment>
  );

这样,您将向用户指示正在获取一些数据。这是一个很好的用户体验方法。

isLoading应该在您的fetchProductsData操作中设置某处,如下所示:

export const fetchProductsData = () => {
  return async (dispatch) => {
    ...
    try {
      dispatch(productsActions.setIsLoading(true));
      const productsData = await fetchData();
      dispatch(productsActions.setProducts(productsData));
    } catch (err) {
      console.log("Error: " + err);
    } finally {
      dispatch(productsActions.setIsLoading(false));
    }
  };
};


推荐阅读