React中useReducer无法正确接收axios获取的products值的问题
问题分析与解决方案
这个问题的核心原因很明确:useReducer的初始状态只会在组件首次渲染时被读取一次,而你的产品数据是通过异步请求获取的——组件第一次渲染时,products还是你设置的初始值(空字符串),这时候useReducer就用这个空值初始化了自己state里的products;等axios请求完成、products状态更新时,useReducer并不会自动重新初始化它的状态,所以你看到state里的products还是空的。
下面给你两种可行的解决方法,推荐第一种,更符合React的状态管理逻辑:
方法一:通过dispatch action更新reducer中的产品数据
这是最标准的处理方式,异步获取到数据后,主动告诉reducer更新状态:
第一步:在Reducer.js中添加更新产品的action类型
export const cartReducer = (state, action) => { switch (action.type) { case "SET_PRODUCTS": return { ...state, products: action.payload }; default: return state; } };
第二步:在Context.js中获取数据后dispatch这个action
我们可以直接去掉多余的products useState,直接在请求完成后分发action:
import axios from "axios"; import React, { createContext, useContext, useEffect, useReducer } from "react"; import { cartReducer } from "./Reducer"; const Cart = createContext(); const Context = ({ children }) => { // 初始state直接设为空数组,和接口返回的类型一致 const [state, dispatch] = useReducer(cartReducer, { products: [], cart: [] }); useEffect(() => { axios.get("/api/products/").then((response) => { // 拿到数据后,通知reducer更新products dispatch({ type: "SET_PRODUCTS", payload: response.data }); }); }, []); return <Cart.Provider value={{ state, dispatch }}>{children}</Cart.Provider>; }; export default Context; export const cartState = () => { return useContext(Cart); };
这样修改后,当axios请求完成,dispatch会触发reducer更新state里的products,你再打印state就能看到完整的产品列表了。
再理清楚原代码的问题
- 组件首次渲染:
products是初始值(空字符串),useReducer用这个值初始化了state.products - axios请求完成:
getProduct(response.data)更新了productsuseState,组件重新渲染 - 但
useReducer不会因为外部的products变化而重新初始化状态——它的初始状态只在第一次渲染时生效,后续必须通过dispatch来修改状态。
所以原代码里的useReducer(cartReducer, { products: products, cart: [], }),只有第一次渲染时的products会被用到,后续products更新也不会影响state.products。
内容的提问来源于stack exchange,提问作者jeffrey mukkath
相关产品推荐
相关产品推荐

