У меня есть список дел. Я переместил заметку об использовании todolist, чтобы она обновлялась только при добавлении todo, но пользовательский интерфейс, похоже, не отражает
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.info("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>
);
};ссылка на codepen: https://codesandbox.io/s/stoic-cloud-phuxsk?file=/src/App.js:0-1082





useMemo React делает поверхностное сравнение через Object.isСогласно документации React для useMemo,
React будет сравнивать каждую зависимость с ее предыдущим значением, используя сравнение
Object.is.
И, согласно веб-документам MDN для Object.is, он определяет, совпадают ли его аргументы. Одно из правил заключается в том, что если «оба являются одним и тем же объектом (что означает, что оба значения ссылаются на один и тот же объект в памяти)», то объект является одним и тем же.
В вашем коде вы вызываете setTodoList(todoArr), а todoArr является ссылкой на todoList. Единственное изменение, которое вы вносите в todoArr, — это вызов todoArr.push. Однако это не создает новую ссылку в памяти. Это просто изменяет todoList и todoArr, потому что они одно и то же.
Что вам нужно сделать, это создать новый массив, а затем вызвать setTodoList. Вы также можете использовать библиотеку, такую как Immer или Immutable.js, чтобы позволить вам «модифицировать» массивы и объекты и вместо этого получить новую копию.
// Native react solution
<button
onClick = {() => {
const todoArr = [...todoList, iptValue]; // Makes a new copy of the array and appends iptValue
setTodoList(todoArr);
setIptValue("");
}}
>
Add Notes
</button>
Это может быть не связано, но я просто заметил, что шаблон обновления также неверен, когда новое состояние основано/связано с его исходным значением, оно должно быть установлено через функцию обратного вызова:
// onClick
() => {
setIptValue("");
setTodoList((todoList) => {
const todoArr = [...todoList];
todoArr.push(iptValue);
return todoList
})
}
Я бы не сказал, что схема обновления неверна. Хотя вы можете использовать обратный вызов, как показано в документации React, на которую вы ссылаетесь. В документации явно упоминается обстоятельство, когда вы хотите обновить одну часть состояния несколько раз. У них также есть целая страница на эту тему: react.dev/learn/queueing-a-series-of-state-updates
Вызов
setTodoList(todoArr);с тем же массивом с точки зренияreferenceне вызовет повторную визуализацию. Вам нужно заменитьconst todoArr = todoList;наconst todoArr = [...todoList];.