React 是否在 hooks 的依赖数组中应用浅/深比较?

Edu*_*Paz 11 javascript arrays compare reactjs react-hooks

const memoizedValue = useMemo(() => {
  // factory function
}, [obj]);
Run Code Online (Sandbox Code Playgroud)

Imagineobj有几个嵌套的 props。

在此示例中使用 useMemo 挂钩:

  • 如果引用发生变化,React 会重新计算工厂函数给出的值吗obj

或者

  • 它应用深/浅比较obj然后重新计算值,如果某些道具发生了变化,无论其参考如何?

Dre*_*ese 11

如果 obj 的引用发生变化,React 会重新计算工厂函数给出的值吗?

据我所知和理解,React 使用浅引用相等性检查,使用Object.is. 强调相关条件。

Object.is()确定两个值是否相同。如果满足以下条件之一,则两个值相同:

  • 两个都undefined
  • 两个都null
  • 两者true或两者false
  • 两个字符串具有相同的长度、相同的字符且顺序相同
  • 都是同一个对象(意味着两个值都引用内存中的同一个对象)
  • 两者BigInts具有相同的数值
  • 两者symbols都引用相同的符号值
  • 两个数字和
    • 两者都+0
    • 均为-0
    • 均为 NaN
    • 或者两者都非零,非 NaN,并且具有相同的值

考虑以下代码:

function App() {
  const [c, setC] = React.useState(0);
  const [obj, setObj] = React.useState({ prop: 10 });

  const forceRender = () => setC((c) => c + 1);

  const memoizedValue1 = React.useMemo(() => {
    console.log("`obj` dependency updated, recomputing value.");
    return obj.prop;
  }, [obj]);

  const memoizedValue2 = React.useMemo(() => {
    console.log("`obj.prop` dependency updated, recomputing value.");
    return obj.prop;
  }, [obj.prop]);

  const immutableHandler = () => {
    setObj(() => {
      console.log("Immutable update returns new object.");
      return { prop: 42 };
    });
    forceRender();
  };

  const mutableHandler = () => {
    setObj((obj) => {
      console.log("Mutable update returns same object with updated property.");
      obj.prop = 13; // DON'T DO THIS IN REAL CODE, IT'S A MUTATION!!
      return obj;
    });
    forceRender();
  };

  return (
    <div className="App">
        <div>memoizedValue1: {memoizedValue1} - memoizedValue2: {memoizedValue2}</div>
      <button type="button" onClick={immutableHandler}>
        Immutable Update
      </button>
      <button type="button" onClick={mutableHandler}>
        Mutable Update
      </button>
      <button type="button" onClick={() => setObj({ prop: 10 })}>
        Reset
      </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  rootElement
);
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root" />
Run Code Online (Sandbox Code Playgroud)

memoizedValue1使用根obj对象值作为依赖项,同时memoizedValue2使用嵌套obj.prop对象值作为依赖项。一个按钮更新并返回一个全新的obj对象引用,而另一个按钮仅更新obj.prop值引用。当整个对象被替换并且是一个新引用时,请注意,两个useMemo钩子回调都会被调用,但是当仅更新嵌套prop值时,只会调用第二个useMemo钩子回调。

结论

在比较 React hook 依赖项时,React 并没有更深入地研究嵌套属性。

  • 正如此的后续操作一样,“hack”得到反应以进行深度比较只是在依赖项数组中感兴趣的对象上使用 JSON.stringify() (4认同)