I have a todo list. I moved the todolist use memo, so that it updates only when todo is added, but ui does not seem to reflect
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>
);
};
codepen link: https://codesandbox.io/s/stoic-cloud-phuxsk?file=/src/App.js:0-1082
2
Answers
React’s
useMemo
does a shallow comparison viaObject.is
According to React’s documentation for
useMemo
,And according to the MDN Web Docs for
Object.is
, it determines whether its arguments are the same. One of the rules is that if "both the same object (meaning both values reference the same object in memory)" then the object is the same.In your code you are calling
setTodoList(todoArr)
andtodoArr
is a reference totodoList
. The only change you make totodoArr
is the call totodoArr.push
. This does not make a new reference in memory though. This simply modifiestodoList
andtodoArr
because they are one in the same.Create a new array
What you need to do is create a new array and then call
setTodoList
. You can also use a library like Immer or Immutable.js to allow you to "modify" arrays and objects and get back a new copy instead.It may be unrelated but I just notice that the update pattern is incorrect either, when a new state is based/related with it’s original value, it should be set via a callback function: