React循环存储数组值至状态失效的解决方法
核心问题点
你的代码存不住数据是以下几个逻辑错误导致的:
useCallback依赖缺失:initFetch里用到了uniqueDCentros但没加到依赖数组,运行时拿的是闭包缓存的旧值- 时序错误:dispatch异步请求后立刻读取store中的topics,此时接口还未返回,store数据未更新,拿到的永远是初始空值
useEffect用法错误:把initFetch直接作为依赖传入,且在effect里同步更新state,要么触发无限重渲染,要么拿不到最新值- 数组更新写法错误:
setUniquetopics([restTopics, ...uniqueTopics])会把整个resTopics数组作为单个元素插入,生成二维数组,无法直接遍历渲染 - 缺少去重逻辑:多个dc拉取的topics存在重复项,直接拼接会出现重复渲染的内容
- 无异常兜底:
JSON.parse直接执行时如果字段为空会直接抛错中断渲染
修正后可直接运行的代码
import { useCallback, useEffect, useState } from 'react'; import { useAuth } from '@/hooks/useAuth'; // 替换成你实际的auth引入路径 import { useDispatch, useSelector } from 'react-redux'; import { getTopicsbyDcentro } from '@/store/actions/topics'; // 替换成你实际的action引入路径 export default function TopicList() { const { user } = useAuth(); const { responsable, editor } = user; // 处理dc列表,加空值兜底防止JSON.parse报错 const uniqueDCentros = Array.from( new Set([ ...(responsable ? JSON.parse(responsable) : []), ...(editor ? JSON.parse(editor) : []) ]) ); const dispatch = useDispatch(); // 从store读取全量topics const storeTopics = useSelector((state) => state.topics); const [uniqueTopics, setUniqueTopics] = useState([]); // 批量拉取所有dc关联的topics const initFetch = useCallback(() => { uniqueDCentros.forEach(dc => { dispatch(getTopicsbyDcentro(dc)); }); }, [dispatch, uniqueDCentros]); // 组件初始化时触发一次拉取 useEffect(() => { initFetch(); }, [initFetch]); // 单独监听store数据变化,自动去重更新本地可渲染列表 useEffect(() => { if (!Array.isArray(storeTopics) || !storeTopics.length) return; // 提取topicName并做全局去重 const allTopicNames = storeTopics.map(topic => topic.topicName); setUniqueTopics(Array.from(new Set(allTopicNames))); }, [storeTopics]); // 直接遍历uniqueTopics渲染Bootstrap卡片即可 return ( <div className="row g-3"> {uniqueTopics.map(topicName => ( <div className="col-md-4" key={topicName}> <div className="card"> <div className="card-body">{topicName}</div> </div> </div> ))} </div> ) }
配套reducer注意项
要确认你的topics reducer是合并新老数据而不是每次覆盖,否则永远只能拿到最后一个dc返回的结果,参考写法:
const topicsReducer = (state = [], action) => { switch(action.type) { case 'GET_TOPICS_SUCCESS': // 合并新老数据+去重,禁止直接return action.payload覆盖旧值 return Array.from(new Set([...state, ...action.payload])); default: return state; } }
内容的提问来源于stack exchange,提问作者ddaudiosolutions
相关产品推荐
相关产品推荐

