React useMemo未更新问题:Todo列表UI不随添加操作刷新
Todo列表添加项后UI不刷新的问题解决
问题场景
开发Todo列表组件时,将Todo列表的渲染逻辑通过useMemo包裹,期望仅在添加Todo项时触发UI更新,但点击添加按钮后,UI并未随之刷新。相关代码如下:
import "./styles.css"; import React from "react"; export default function App() { return ( <div className="App"> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> <TodoList /> </div> ); } const Todo = ({ taskName }) => { console.log("in here todo"); return <div>{taskName}</div>; }; const TodoList = () => { const [todoList, setTodoList] = React.useState([]); const [iptValue, setIptValue] = React.useState(""); const todoWrapper = React.useMemo(() => { return ( <> {(todoList || []).map((item) => ( <Todo taskName={item} key={item} /> ))} </> ); }, [todoList]); return ( <div> {todoWrapper} <input type="text" onChange={(ev) => { setIptValue(ev.target.value); }} /> <button onClick={() => { const todoArr = todoList; todoArr.push(iptValue); setIptValue(""); setTodoList(todoArr); }} > Add Notes </button> </div> ); };
问题原因
核心问题是违反了React state的不可变性原则:
const todoArr = todoList只是复制了原数组的引用,并非创建新数组。- 调用
todoArr.push(iptValue)后,原state数组的内容被修改,但数组的引用并未改变。 - 当调用
setTodoList(todoArr)时,React对比前后state的引用,发现是同一个对象,因此判定state未发生变化,不会触发组件重渲染,useMemo依赖的todoList也不会更新,最终导致UI无刷新。
修复方案
需要创建新的数组来更新state,确保引用发生变化。可以通过以下几种方式实现:
方法1:使用扩展运算符创建新数组
<button onClick={() => { // 创建包含新项的新数组 setTodoList([...todoList, iptValue]); setIptValue(""); }} > Add Notes </button>
方法2:使用concat方法
<button onClick={() => { setTodoList(todoList.concat(iptValue)); setIptValue(""); }} > Add Notes </button>
方法3:使用slice复制数组后再push
<button onClick={() => { const todoArr = todoList.slice(); // 复制原数组得到新引用 todoArr.push(iptValue); setTodoList(todoArr); setIptValue(""); }} > Add Notes </button>
修复后,每次添加Todo时都会生成新的数组引用,React会检测到state变化,触发组件重渲染,useMemo也会因todoList更新而重新执行,UI就能正常显示新添加的Todo项。
内容的提问来源于stack exchange,提问作者Geeky
相关产品推荐
相关产品推荐

