React出现Too many re-renders无限重渲染错误如何解决
无限重渲染问题根因
- 核心问题是你把
store.dispatch直接写在了组件顶层函数体中,没有任何包裹限制。每次组件渲染都会执行该dispatch修改Redux的toDos数据,而你又通过useSelector监听了store.toDos,数据更新就会触发组件重渲染,最终形成「渲染→dispatch改数据→重渲染→再dispatch」的无限循环,和setTodosState本身无关。 - 次要问题是你在
map遍历todosState时直接修改原对象o.user = user,属于直接变更本地状态的不当操作,会引发预期外的引用变化问题。
修复方案
最小改动的修复逻辑是把数据处理和dispatch的逻辑放到useEffect中,仅在接口返回的users和todosState加载完成后执行,同时修改map逻辑为返回新对象,不要修改原状态:
import React, { useEffect } from 'react'; import { useState } from 'react'; import { useSelector } from 'react-redux'; import store from '../../store'; import ToDoAdder from '../ToDoAdder/ToDoAdder'; function ToDoList() { const [users, setUsers] = useState([]); const [todosState, setTodosState] = useState([]); useEffect(() => { fetchUsers(); fetchData(); }, []); // 仅在users、todosState更新时执行数据处理和dispatch useEffect(() => { // 两个接口都返回数据后才执行后续逻辑,避免空数据dispatch if (users.length === 0 || todosState.length === 0) return; const todosWithUser = todosState.map((o) => { const user = users.filter((i) => o.userId === i.id)[0]; // 返回新对象,不修改原状态中的元素 return {...o, user}; }); store.dispatch({ type: "add/todoArray", payload: { todos: todosWithUser } }); }, [users, todosState]) const fetchUsers = async () => { const data = await fetch(`https://jsonplaceholder.typicode.com/users/`); const res = await data.json(); console.log(res, 0); setUsers(res); }; const fetchData = async () => { const data = await fetch('https://jsonplaceholder.typicode.com/todos/'); const res = await data.json(); const needed = res.slice(0, 10); setTodosState(needed); return res; }; const todos = useSelector((store) => store.toDos); return ( /* some statement */ ); } export default ToDoList;
可选优化
如果你的todo数据最终都存在Redux中,可以直接把接口请求和数据处理逻辑都放到Redux的异步处理流程(比如thunk/saga)中,组件不需要再维护users和todosState两个本地状态,进一步简化代码。
内容的提问来源于stack exchange,提问作者Majid Ainizoda
相关产品推荐
相关产品推荐

