RTK createAsyncThunk更新状态后useSelector返回初始值问题
问题描述
我尝试通过HTTP GET请求配合createAsyncThunk实现随机用户的会话鉴权,在App.js的组件挂载钩子中拉取用户数据。我可以在浏览器网络面板中看到对应的GET请求,也能在Redux DevTools中查看到拉取后的最新状态,但TopBar.js中useSelector返回的始终是拉取前的初始状态。
TopBar.js 控制台用户日志截图:
相关代码
App.js 代码
const dispatch = useDispatch(); useEffect(() => { dispatch(fetchRandomUserData()) }, [dispatch]);
authSlice.js 代码
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; const initialState = { isLoggedIn: true, user: {}, loading: false, error: null, }; export const fetchRandomUserData = createAsyncThunk( 'auth/fetchRandomUser', async () => { try { const response = await fetch('https://randomuser.me/api/'); const data = await response.json(); return data.results[0]; } catch (error) { throw Error(error); } } ); const authSlice = createSlice({ name: 'auth', initialState, reducers: { logout(state, action) { state.isLoggedIn = false; }, }, extraReducers: { [fetchRandomUserData.pending]: (state, action) => { state.loading = true; state.error = null; }, [fetchRandomUserData.fulfilled]: (state, action) => { console.log("action.payload",action.payload); state.user = action.payload; state.loading = false; }, [fetchRandomUserData.rejected]: (state, action) => { state.error = action.error.message; state.loading = false; }, }, }); export const { logout } = authSlice.actions; export default authSlice.reducer;
store.js 代码
import { configureStore } from '@reduxjs/toolkit'; // import booksReducer from './reducers/booksReducer'; import booksReducer from './slices/bookSlice'; import authReducer from './slices/authSlice'; const store = configureStore({ reducer: { books: booksReducer, auth: authReducer }, }); export default store;
TopBar.js 代码
export default function TopBar(): JSX.Element { const user = useSelector((state: any) => state.auth); console.log("topbar",user); // 始终返回初始状态 //.... }
问题原因&解决方案
这个问题和thunk、slice的业务写法无关,DevTools能看到状态更新说明数据流逻辑完全正常,问题出在Store连接层,按优先级排查:
- 首先检查项目入口文件(通常是
main.jsx/index.jsx)的<Provider>配置:必须全局只存在一个Provider包裹整个应用,且传入的store是你store.js中导出的、注册了authReducer的唯一实例,不要在其他文件重复调用configureStore创建新store。 - 确认TopBar组件在Provider的子树范围内:如果TopBar写在了
<Provider store={store}>标签的外层,它会读取不到你更新的store状态。
入口文件正确写法参考:import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' import store from './store' import { Provider } from 'react-redux' ReactDOM.createRoot(document.getElementById('root')!).render( <Provider store={store}> <App /> {/* 所有用到useSelector/useDispatch的组件,必须放在这对Provider标签内部 */} </Provider> ) - 最后检查
useSelector的引入来源,必须是从react-redux包引入,不要引错自定义同名方法或其他包的同名API。
你当前useSelector((state) => state.auth)的写法本身没有问题,Redux对selector返回的对象做浅比较,状态更新后会正常触发组件重渲染,不需要修改这部分逻辑。
内容的提问来源于stack exchange,提问作者Sergey Arenzon
相关产品推荐
相关产品推荐

