React的`useMemo`不会更新。

huangapple go评论51阅读模式
英文:

React Use memo does not update

问题

以下是您提供的内容的翻译:

"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"

"我有一个待办事项列表。我使用 memo 移动了待办事项列表,以便它只在添加待办事项时更新,但界面似乎没有反映出来。"

代码部分不包括在翻译内。如果您需要进一步的帮助,请随时提问。

英文:

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

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

import &quot;./styles.css&quot;;
import React from &quot;react&quot;;

export default function App() {
  return (
    &lt;div className=&quot;App&quot;&gt;
      &lt;h1&gt;Hello CodeSandbox&lt;/h1&gt;
      &lt;h2&gt;Start editing to see some magic happen!&lt;/h2&gt;
      &lt;TodoList /&gt;
    &lt;/div&gt;
  );
}

const Todo = ({ taskName }) =&gt; {
  console.log(&quot;in here todo&quot;);
  return &lt;div&gt;{taskName}&lt;/div&gt;;
};

const TodoList = () =&gt; {
  const [todoList, setTodoList] = React.useState([]);
  const [iptValue, setIptValue] = React.useState(&quot;&quot;);
  const todoWrapper = React.useMemo(() =&gt; {
    return (
      &lt;&gt;
        {(todoList || []).map((item) =&gt; (
          &lt;Todo taskName={item} key={item} /&gt;
        ))}
      &lt;/&gt;
    );
  }, [todoList]);
  return (
    &lt;div&gt;
      {todoWrapper}
      &lt;input
        type=&quot;text&quot;
        onChange={(ev) =&gt; {
          setIptValue(ev.target.value);
        }}
      /&gt;
      &lt;button
        onClick={() =&gt; {
          const todoArr = todoList;
          todoArr.push(iptValue);
          setIptValue(&quot;&quot;);
          setTodoList(todoArr);
        }}
      &gt;
        Add Notes
      &lt;/button&gt;
    &lt;/div&gt;
  );
};

<!-- end snippet -->

codepen link: https://codesandbox.io/s/stoic-cloud-phuxsk?file=/src/App.js:0-1082

答案1

得分: 1

React的useMemo通过Object.is进行浅层比较

根据React关于useMemo的文档

React会使用Object.is比较每个依赖项与其先前的值。

而根据MDN Web Docs关于Object.is的文档,它确定其参数是否相同。其中一个规则是,如果“两者是同一个对象(意思是两个值引用内存中的同一个对象)”,那么这个对象是相同的。

在你的代码中,你调用了setTodoList(todoArr),而todoArr是对todoList的引用。你对todoArr所做的唯一更改是调用todoArr.push。但这并不会在内存中创建一个新的引用。这只是修改了todoListtodoArr,因为它们是一样的。

创建一个新数组

你需要做的是创建一个新数组,然后调用setTodoList。你也可以使用类似Immer或Immutable.js这样的库,允许你“修改”数组和对象,并获得一个新的副本。

// Native react solution
<button
  onClick={() => {
    const todoArr = [...todoList, iptValue]; // 创建一个新的数组副本并追加iptValue
    setTodoList(todoArr);
    setIptValue("");
  }}
>
  添加笔记
</button>
英文:

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.is comparison.

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
&lt;button
  onClick={() =&gt; {
    const todoArr = [...todoList, iptValue]; // Makes a new copy of the array and appends iptValue
    setTodoList(todoArr);
    setIptValue(&quot;&quot;);
  }}
&gt;
  Add Notes
&lt;/button&gt;

答案2

得分: 1

以下是您要翻译的内容:

可能与此无关,但我刚刚注意到更新模式也是不正确的,当新状态基于/与其原始值相关联时,应通过回调函数进行设置(参见通过回调函数更新状态):

// 点击事件
() => {
    setIptValue("");
    setTodoList((todoList) => {
        const todoArr = [...todoList];
        todoArr.push(iptValue);
        return todoList
    })
}
英文:

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:

// onClick
() =&gt; {
    setIptValue(&quot;&quot;);
    setTodoList((todoList) =&gt; {
        const todoArr = [...todoList];
        todoArr.push(iptValue);
        return todoList
    })
}

huangapple
  • 本文由 发表于 2023年4月20日 05:06:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76058805.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定