使用Redux Toolkit的createAsyncThunk获取数据后state不更新
问题原因
- Slice配置语法错误:你定义
userSlice时,reducers: {},后面多写了一个多余的闭合大括号和逗号,导致extraReducers根本没有被传入createSlice的配置项中,请求成功后的更新逻辑完全不会执行。 - 状态更新写法错误:就算修复了上述语法错误,你在
extraReducers中直接对state参数赋值state = {...}的写法也是无效的。Redux Toolkit 内部集成了 Immer 库,支持两种更新状态的写法:要么直接修改state对象的属性,要么显式return新的状态对象。直接赋值给局部参数state,既没有修改Immer代理的状态,也没有返回新对象给Redux,状态不会更新。 - 组件读取状态时机错误:
useSelector获取的user属于当前渲染闭包中的值,哪怕你await等待异步请求执行完成,当前渲染周期的user仍然是初始值,只有组件触发重新渲染后,才能拿到更新后的状态,所以你在cacheResources函数内打印的永远是当前渲染的旧值。 - 异步请求逻辑存在语法和异常隐患:你定义
fetchUserById时,await API.getUser, { userID: userId }))存在语法错误,多了右括号且传参方式错误。如果请求触发catch分支,response会是undefined,后续执行return response.data.getUser会直接抛出异常。
解决方案
1. 修正userSlice.js代码
先删掉多余的闭合大括号,再修改状态更新逻辑,两种写法二选一即可:
写法1:直接修改state属性(推荐,Immer会自动处理 immutable 更新)
export const fetchUserById = createAsyncThunk( 'user/fetchUserById', async (userId, thunkAPI) => { try { // 修正请求传参语法错误 const response = await API.getUser({ userID: userId }); return response.data.getUser } catch (e) { console.log(e) // 可选:抛出异常让thunk进入rejected状态,方便后续处理错误 return thunkAPI.rejectWithValue(e) } } ); export const userSlice = createSlice({ name: 'user', initialState: {user: {}}, reducers: {}, // 删掉原来这里多余的闭合大括号 extraReducers: (builder) => { builder.addCase(fetchUserById.fulfilled, (state, action) => { // 直接修改state的属性即可 state.user = action.payload }); } }); export default userSlice.reducer
写法2:显式返回新状态对象
extraReducers: (builder) => { builder.addCase(fetchUserById.fulfilled, (state, action) => { return { ...state, user: action.payload } }); }
2. 修正组件中状态验证方式
如果要确认状态是否更新,不要在请求触发函数内打印,改为在组件顶层打印或者用useEffect监听user变化:
import AppLoading from 'expo-app-loading'; import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux' import { fetchUserById } from '../../redux/slices/userSlice'; const AppLoadingScreen = (props) => { const user = useSelector(state => state.userReducer.user) const dispatch = useDispatch() // 组件重新渲染时会打印最新的user console.log("最新user状态:", user) // 监听user变化,更新时触发回调 useEffect(() => { console.log("user已更新:", user) }, [user]) const cacheResources = async () => { await dispatch(fetchUserById('00')); } return ( <AppLoading startAsync={cacheResources} onFinish={() => {props.setIsReady(true)}} onError={console.warn} /> ); }
内容的提问来源于stack exchange,提问作者man517
相关产品推荐
相关产品推荐

