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
please help here
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
>Solution :
React’s useMemo does a shallow comparison via Object.is
According to React’s documentation for useMemo,
React will compare each dependency with its previous value using the
Object.iscomparison.
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) and todoArr is a reference to todoList. The only change you make to todoArr is the call to todoArr.push. This does not make a new reference in memory though. This simply modifies todoList and todoArr 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.
// Native react solution
<button
onClick={() => {
const todoArr = [...todoList]; // Makes a new copy of the array
todoArr.push(iptValue);
setIptValue("");
setTodoList(todoArr);
}}
>
Add Notes
</button>