状态为空,在 useEffect 钩子之后

时间:2021-06-24 01:00:55

标签: javascript reactjs react-redux react-hooks

我试图通过在 useEffect 中调度方法来设置产品。然而,状态仍然说空。

index.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;

产品在一个循环后仍然显示为空,显然它需要第二个循环才能使该状态改变。不知道如何让它在一个周期内改变。我需要将 useEffect 放在父级中吗?

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

 {products !== null && <Products 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;

products-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);
    }
  };
};

1 个答案:

答案 0 :(得分:1)

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