使用@reduxjs/toolkit拉取大学列表时报proxy已撤销错误如何解决?
问题原因
你的核心错误是不应该在Redux Toolkit的reducer函数中执行异步请求逻辑:
- RTK的reducer是纯函数,内部你拿到的
state是Immer库生成的代理对象,reducer同步执行完成后这个代理就会被自动撤销回收 - 你把接口请求放在reducer里,请求的
then回调是异步执行的,等回调触发时state代理已经失效了,操作state.universities.push自然就会抛出"代理已撤销"的报错
另外还有两个隐藏问题:
- 你封装的axios请求URL里多了多余空格:
search? country=中?后面的空格会导致请求参数异常 - 组件里直接在函数顶层执行
dispatch,会导致每次组件渲染都重复触发接口请求
修复方案
你需要使用RTK官方提供的createAsyncThunk来处理异步接口逻辑,调整代码如下:
1. 修正UniversityService的请求URL
import axios from "axios"; export default class UniversityService { getUniversitiesByCountry(countryName) { // 去掉?后的多余空格 return axios .get("http://universities.hipolabs.com/search?country=" + countryName) .then((response) => response); } }
2. 改造UniversitiesSlice,引入createAsyncThunk处理异步
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit"; import UniversityService from "../../service/UniversityService"; const universityService = new UniversityService(); // 定义异步请求thunk export const fetchUniversitiesByCountry = createAsyncThunk( "universities/fetchByCountry", async (countryName) => { const response = await universityService.getUniversitiesByCountry(countryName); return response.data; } ); export const universitiesSlice = createSlice({ name: "universities", initialState: { universities: [], }, reducers: {}, // 监听异步请求的完成状态,更新state extraReducers: (builder) => { builder.addCase(fetchUniversitiesByCountry.fulfilled, (state, action) => { // 这里是同步执行,state代理还未失效,可以直接操作 state.universities = action.payload; // 如果需要追加而非覆盖,就用state.universities.push(...action.payload) }); }, }); export default universitiesSlice.reducer;
3. 修正ListPage的dispatch触发逻辑
import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { fetchUniversitiesByCountry } from './对应的slice路径'; export default function ListPage() { const dispatch = useDispatch(); const universities = useSelector((state) => state.universities.universities); // 把dispatch放在useEffect里,只在组件挂载时触发一次 useEffect(() => { dispatch(fetchUniversitiesByCountry("Turkey")); }, [dispatch]); console.log(universities); return ( <div> <Table striped bordered hover> <thead> <tr> <th>#</th> <th>University Name</th> <th>Domain</th> <th>Web Page</th> </tr> </thead> <tbody> {universities.map((university, index) => ( // 直接用map的第二个参数index作为key,性能优于indexOf <tr key={index}> <td>{index + 1}</td> <td>{university.name}</td> <td>{university.domains[0]}</td> <td> <a style={{ textDecoration: "none" }} href={university.web_pages[0]} target="_blank" rel="noreferrer"> {university.web_pages[0]} </a> </td> </tr> ))} </tbody> </Table> </div> ); }
内容的提问来源于stack exchange,提问作者user15992593
相关产品推荐
相关产品推荐

