React基于过滤条件重渲染数组出现过多重渲染错误如何解决?
问题修复方案
错误根因
你在组件函数的顶级作用域直接调用setTasks修改状态,触发了死循环:
- React组件每次渲染都会执行函数内所有顶级代码
- 只要
showAll为false,就会执行setTasks更新状态 - 状态更新会触发组件重新渲染,又会再次执行到这段
setTasks逻辑,无限循环导致过多重渲染报错
另外直接修改原始tasks状态会覆盖接口返回的全量数据,后续切换回「展示全部」时也无法恢复完整任务列表。
修复步骤
保留原始tasks状态存储全量接口数据,不要直接修改它,渲染前基于showAll的状态动态计算要展示的任务列表即可,无需额外维护状态。
修正后的代码
const MainPage = () => { const [tasks, setTasks] = useState([]); const [showAll, setShowAll] = useState(true); useEffect( ()=> { axios.get('api/tasks/') .then( response => { setTasks(response.data.tasks); }) .catch(err => { console.log('error'); }) }, []); const fetchItems = (cat_id) => { axios.get('/api/tasks/') .then( response => { setTasks(response.data.tasks); }) .catch(err => { console.log('error'); }) }; const handleCheckboxChange = (e) => { // 注意setShowAll是异步更新,此处打印的showAll为更新前的旧值 setShowAll(!showAll) }; // 动态计算要展示的任务列表,不修改原始状态 const displayedTasks = showAll ? tasks : tasks.filter(v => !v.completed); return ( <div> <label className="checkb"> <input name="show_all" id="show_all" type="checkbox" checked={showAll} onChange={handleCheckboxChange} /> 展示全部 </label> <br/> { displayedTasks && displayedTasks.map((task, index) => { return ( <div key={index} className="task-wrapper flex-wrapper"> <div > { !task.completed ? ( <span> {index +1}. {task.task_description} </span> ) : (<strike> {index +1}. {task.task_description} </strike>) } </div> <div> <button onClick={()=> modalClick(task)} className="btn btn-sm btn-outline-warning">编辑</button> <span> </span> </div> </div> ) })} </div> ); }; export default MainPage;
可选优化点
如果任务列表数据量很大,可以用useMemo缓存计算结果,避免每次渲染都重新过滤:
const displayedTasks = useMemo(() => { return showAll ? tasks : tasks.filter(v => !v.completed) }, [showAll, tasks])
内容的提问来源于stack exchange,提问作者jay queue
相关产品推荐
相关产品推荐

