ReactJS Redux Toolkit根据ID取API数据:重复调用无法获取新ID数据
问题解决思路
1. 换ID不发起新请求的原因及解决
核心原因
要么是createAsyncThunk的默认缓存机制在参数相同时复用了旧请求结果,要么是组件没有在参数变化时重新触发dispatch。
解决步骤
步骤1:确保组件在参数变化时重新dispatch
检查组件中触发请求的逻辑,比如useEffect的依赖项是否包含scoreId和apiAddress,确保参数变化时重新调用thunk:
// 正确示例:依赖项包含所有变化的参数 useEffect(() => { dispatch(getScoreData({ apiAddress, scoreId })); }, [apiAddress, scoreId, dispatch]);
步骤2:强制禁用thunk的缓存(可选)
如果确实需要每次调用都发起新请求,不管参数是否相同,可以给createAsyncThunk添加condition配置:
export const getScoreData = createAsyncThunk( 'contentitem/scoredata', async (params) => { try { const res = await axios.get(`${params.apiAddress}api/v2/scores/${params.scoreId}`); return res.data; } catch (err) { console.error(err); throw err; // 必须抛出错误,让rejected状态正确触发 } }, { // 强制每次调用都发起新请求 condition: () => true } );
注意:原代码中
then的错误处理会吞掉错误,导致rejected状态无法触发,建议改成try/catch并抛出错误。
2. 复用存储区域存同结构不同类型数据
当前的state.data是单个对象,每次请求会覆盖旧数据,需要改成键值对结构,用唯一标识(比如apiAddress+scoreId的组合)作为key,存储不同请求的结果:
修改initialState
const initialState = { // 键值对存储不同请求的数据,key为唯一标识 items: {}, loading: false, complete: false };
修改slice的extraReducers
改用RTK推荐的builder语法,根据请求参数生成唯一key,将数据存入对应位置:
export const scoreSlice = createSlice({ name: 'contentitem', initialState, reducers: {}, extraReducers: (builder) => { builder .addCase(getScoreData.pending, (state, { meta }) => { state.loading = true; state.complete = false; // 生成唯一key const key = `${meta.arg.apiAddress}-${meta.arg.scoreId}`; // 初始化该条目的加载状态 state.items[key] = { ...state.items[key], loading: true }; }) .addCase(getScoreData.fulfilled, (state, { payload, meta }) => { state.loading = false; state.complete = true; const key = `${meta.arg.apiAddress}-${meta.arg.scoreId}`; // 存储当前请求的数据 state.items[key] = { data: payload, loading: false, complete: true }; }) .addCase(getScoreData.rejected, (state, { meta }) => { state.loading = false; state.complete = true; const key = `${meta.arg.apiAddress}-${meta.arg.scoreId}`; // 标记请求失败 state.items[key] = { ...state.items[key], loading: false, complete: true, hasError: true }; }); } });
组件中获取对应数据
使用时根据当前的apiAddress和scoreId生成key,从items中取出对应数据:
const { items } = useSelector(state => state.contentitem); const currentKey = `${apiAddress}-${scoreId}`; const currentData = items[currentKey]?.data; const isLoading = items[currentKey]?.loading || false;
内容的提问来源于stack exchange,提问作者KenPx
相关产品推荐
相关产品推荐

