Redux状态更新成功但对应React组件未重新渲染该如何解决?
问题原因
原始代码的核心问题
你在forEach循环中使用异步请求获取单条宝可梦数据,forEach不会等待async回调执行完成,会直接执行后续的dispatch逻辑,此时你传给dispatch的pokemonsArray是空数组。后续所有请求完成后你只是对原数组执行push操作,没有修改数组的引用地址,Redux默认通过引用对比判断状态是否变化,因此不会触发组件重新渲染。
当你切换路由再切回时,PokemonsDisplay组件重新挂载,useSelector会读取此时已经被push完所有数据的数组内容,所以列表能正常显示。
后续修改后action无法触发的问题
你写的initPokemons是Redux thunk格式的action创建函数,必须传给dispatch执行才能生效,你直接调用initPokemons(pokemons)只是生成了一个待执行的函数,没有真正发送action到reducer。同时你把异步逻辑放到了fetchEverything中,这个函数不是thunk,拿不到dispatch方法,自然无法触发状态更新。
修复方案
1. 替换forEach为Promise.all等待所有异步请求完成
不要用forEach处理批量异步请求,改用map生成所有请求的Promise数组,通过Promise.all等待全部请求完成后再生成完整的宝可梦数组,保证dispatch时拿到的是完整数据,且是全新的数组引用。
2. 修正后的完整代码
// pokemonsReducer.js import getPokemons from '../services/pokemons'; import axios from 'axios'; import { loadPokemonsFromLS, savePokemonsList } from '../utils/localStoragePokemons'; const pokemonsReducer = (state = [], action) => { switch(action.type){ case 'INIT_POKEMONS': // 返回全新数组,确保Redux检测到状态变更 return [...action.payload.pokemons]; default: return state; }; }; export const fetchPokemons = (limit, offset) => { return async dispatch => { try { const pokemons = loadPokemonsFromLS(limit, offset); dispatch({ type: 'INIT_POKEMONS', payload: { pokemons } }); } catch (error) { const pokemonsData = await getPokemons.getPokemons(limit, offset); // 生成所有单条宝可梦请求的Promise数组 const pokemonRequests = pokemonsData.results.map(r => axios.get(r.url)); // 等待所有请求完成 const pokemonResponses = await Promise.all(pokemonRequests); // 组装完整宝可梦数组 const pokemonsArray = pokemonResponses.map(res => res.data); // 组装本地存储用的对象 const pokemonsObject = pokemonsArray.reduce((acc, cur, index) => { acc[index] = cur; return acc; }, {}); savePokemonsList(limit, offset, pokemonsObject); dispatch({ type: 'INIT_POKEMONS', payload: { pokemons: pokemonsArray } }); } }; }; export default pokemonsReducer;
3. 原有组件调用逻辑无需修改
保留App.js中原来的dispatch(fetchPokemons(limit, offset))调用即可,你后续写的fetchEverything不符合thunk规范,直接废弃不用。
内容的提问来源于stack exchange,提问作者pabloF
相关产品推荐
相关产品推荐

