Redux Toolkit createAsyncThunk无返回值 useSelector取数报错
问题现象
在React项目中使用Redux Toolkit的createAsyncThunk搭配Axios处理异步请求,初期功能运行正常;仅调整SCSS相关代码后,Chrome控制台抛出TypeError: Cannot read properties of undefined (reading 'map')错误。全程未修改Redux与thunk相关逻辑,但出现两个异常:
useSelector无法获取对应store状态- 原本可正常响应的接口无返回
相关代码
thunk与slice定义
export const getTopBanners = createAsyncThunk( 'home/getTopBanners', async ()=>{ console.log('hello?'); const response = await axiosGetTopBanner(); console.log('res:'+response); return response.banners } ) export const topBannerSlice = createSlice({ name:'topBanner', initialState:{ pics:[], isLoading:false }, extraReducers:{ [getTopBanners.pending]:(state)=>{ state.isLoading = true; }, [getTopBanners.fulfilled]:(state,action)=>{ state.pics = action.payload; state.isLoading = false; }, [getTopBanners.rejected]:(state)=>{ state.isLoading = false; } } })
组件使用代码
const dispatch = useDispatch(); // 此处无法获取到对应状态 const topBanners = useSelector((state) => state.topBanner.pics); useEffect(() => { dispatch(getTopBanners()); }, [dispatch]);
store配置代码
const store = configureStore({ reducer:{ topBanner:topBannerReducer, recommendData:recommendDataReducer } })
问题排查与修复
这个报错和SCSS修改本身没有直接关联,是之前隐藏的写法问题在热更新/代码重载后触发了,按以下顺序排查即可:
- 修正extraReducers的写法
你现在用的对象key映射action type的写法,是Redux Toolkit 1.x版本的兼容写法,RTK 2.0之后默认不再支持这种写法,必须用builder回调形式注册异步action的处理逻辑,否则thunk的pending/fulfilled/rejected三个状态都不会被slice正确监听,请求派发后状态不会更新,state.topBanner会直接变成undefined,组件里对topBanners调用map就会抛出你看到的错误。
修正后的slice代码:export const topBannerSlice = createSlice({ name:'topBanner', initialState:{ pics:[], isLoading:false }, extraReducers: (builder) => { builder .addCase(getTopBanners.pending, (state) => { state.isLoading = true; }) .addCase(getTopBanners.fulfilled, (state, action) => { state.pics = action.payload; state.isLoading = false; }) .addCase(getTopBanners.rejected, (state) => { state.isLoading = false; }) } }) - 给异步请求加兜底逻辑
现在的thunk逻辑没有错误捕获,一旦接口返回结构异常(比如response上没有banners字段),thunk会直接进入rejected状态,而rejected处理逻辑里没有给pics设置默认空数组,也会触发map的报错。可以给thunk加一层容错:export const getTopBanners = createAsyncThunk( 'home/getTopBanners', async (_, { rejectWithValue }) => { try { const response = await axiosGetTopBanner(); return response?.banners || []; } catch (err) { return rejectWithValue(err); } } ) - 检查Provider包裹层级
如果调整SCSS的时候不小心改动了根组件的代码,确认下<Provider store={store}>是包裹在所有用到Redux状态的业务组件外层,没有出现组件在Provider外层渲染的情况,这种场景也会导致useSelector拿不到正确的store状态。
内容的提问来源于stack exchange,提问作者ASElieen
相关产品推荐
相关产品推荐

