React+Redux Toolkit如何避免同一组件多处渲染重复发API请求
问题原因
两个Navbar组件几乎同时挂载时,内部的useEffect会并发触发dispatch(fetchNavigation),此时第一次请求还未完成,state中的loaded字段仍为初始的false,因此两次dispatch都会触发网络请求,你之前的方案未生效就是因为没有处理请求进行中的状态。
解决方案
方案1:改造thunk添加前置校验(推荐,组件逻辑闭环)
1. 先完善navigation slice的状态,新增loading字段处理请求中状态
import { createSlice } from "@reduxjs/toolkit"; import { fetchNavigation } from "../services/fetchNavigation" const initialState = { "count": 0, "next": null, "previous": null, "navs": [], "loaded": false, "loading": false // 新增:标记请求是否正在进行 } const navSlice = createSlice({ name: 'navigation', initialState: initialState, extraReducers: { // 新增pending状态处理 [fetchNavigation.pending]: (state) => { state.loading = true }, [fetchNavigation.fulfilled]: (state, action) => { state.count = action.payload.count; state.next = action.payload.next; state.previous = action.payload.previous; state.loaded = true state.navs = action.payload.results; state.loading = false // 请求完成重置loading }, // 新增rejected状态处理,避免请求失败后永远处于loading [fetchNavigation.rejected]: (state) => { state.loading = false } }, }) export default navSlice.reducer
2. 改造fetchNavigation异步action,发起请求前先校验状态
利用createAsyncThunk payloadCreator的第二个参数拿到全局state,判断如果已经加载完成、或者正在加载中,就直接终止请求逻辑:
import { createAsyncThunk } from "@reduxjs/toolkit"; import { instance } from "../../API/config" export const fetchNavigation = createAsyncThunk( "navigation/fetchNavigation", async (_, { getState, rejectWithValue }) => { // 先从state中拿到navigation模块的状态 const { navigation } = getState() // 已经加载完成 或者 正在加载中,都不发起新请求 if (navigation.loaded || navigation.loading) { return rejectWithValue('无需重复请求导航数据') } try { const response = await instance.get(`nav/`) return response.data } catch (err) { return rejectWithValue(err.message) } } );
3. (可选双重保险)组件内dispatch前加判断
也可以在Navbar组件的useEffect里先判断状态,再决定是否dispatch:
useEffect(() => { // 只有未加载、也不在加载中时才发起请求 if (!navigation.loaded && !navigation.loading) { dispatch(fetchNavigation()); } }, [dispatch, navigation.loaded, navigation.loading])
方案2:请求逻辑上移到公共父组件
如果你的两个Navbar有共同的父组件(比如全局Layout组件、App根组件),可以直接把dispatch(fetchNavigation)的逻辑移到父组件的useEffect里执行,两个Navbar组件删掉内部的dispatch逻辑,从源头保证只会触发一次请求。
内容的提问来源于stack exchange,提问作者Spell
相关产品推荐
相关产品推荐

