我试图通过在 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);
}
};
};
答案 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));
}
};
};