React Typescript+Redux调用API更新状态时报proxy已撤销错误如何解决
问题原因
核心错误是在Redux Toolkit的reducer函数中编写了异步逻辑:
- RTK的reducer底层用Immer库生成可修改的state代理对象,reducer同步执行完成后这个代理会立即被撤销回收
- 你把
fetchInitData异步请求写在了initData的reducer回调里,请求返回后执行then回调修改state的时候,代理已经被销毁,所以触发proxy revoked报错
修复方案
步骤1:调整questionReducers.ts,用createAsyncThunk封装异步逻辑
reducer必须是纯同步函数,所有异步请求都要放到RTK官方提供的thunk中间件中处理,修正后代码如下:
import {createAction, createReducer, createAsyncThunk} from '@reduxjs/toolkit'; import {fetchInitData} from './questionAPI'; import {AnswerInterface} from "../types/AnswerInterface"; import {Questions} from "../types/Questions"; import {RootState} from "./store"; interface QuestionsState { data: Questions, status: 'loading' | 'loaded' | 'error' } const initialState = { data: { question: { text: '', imageURL: '' }, answers: [], }, status: 'loading', } as QuestionsState export const appState = (state: RootState) => state; export const addAnswer = createAction<AnswerInterface>('question/addAnswer') // 封装异步请求thunk export const fetchInitDataThunk = createAsyncThunk('app/fetchInitData', async () => { return await fetchInitData(); }) export const questionReducer = createReducer(initialState, (builder) => { builder // 匹配异步请求三个状态 .addCase(fetchInitDataThunk.pending, (state) => { state.status = 'loading'; }) .addCase(fetchInitDataThunk.fulfilled, (state, action) => { state.data = action.payload; state.status = 'loaded'; }) .addCase(fetchInitDataThunk.rejected, (state) => { state.status = 'error'; }) .addCase(addAnswer, (state, action) => { state.data.answers.push(action.payload); localStorage.setItem('data', JSON.stringify(state.data)); }) })
步骤2:修正App.tsx的错误
修复导入拼写错误、useEffect无依赖导致无限触发的问题:
import React, {useEffect} from 'react'; import styles from './App.module.css'; import { useAppSelector, useAppDispatch } from './app/hooks' // 修正导入拼写错误,替换为thunk方法 import {fetchInitDataThunk, appState} from "./app/questionReducers"; const App:React.FC = () => { const state = useAppSelector(appState); const dispatch = useAppDispatch(); // 加空依赖数组,仅组件挂载时触发一次请求 useEffect(() => { dispatch(fetchInitDataThunk()); }, [dispatch]); return ( <div className={styles.App}> {state.status === 'loading' && <div>Loading...</div>} {state.status === 'loaded' && <div>Loaded...</div>} {state.status === 'error' && <div>加载失败,请稍后重试</div>} </div> ); } export default App;
注意事项
- 所有异步、副作用逻辑禁止直接写在reducer中,必须通过thunk、saga这类中间件实现
- useEffect必须明确指定依赖数组,避免意外重复执行逻辑
内容的提问来源于stack exchange,提问作者Avishai Peretz
相关产品推荐
相关产品推荐

