useEffect 中使用 memoized object 时可以使用 useMemo 吗?

Can we use useMemo when memoized object is used in useEffect?

想象一下这种情况。

接收 object 并基于 object 的属性进行一些计算并 returns 结果的挂钩。

export const useTestHook = (someOject) => {
  const [updated, set] = useState({ val1: null, val2: null });

  useEffect(() => {
    set({
      val1: `${someOject.val1}_-`,
      val2: `${someOject.val2}_-`,
    })
  }, [someOject]);

  return updated;
}

使用挂钩的组件将这些值分开,因此需要初始化新的 object 以便将其传递给挂钩。钩子的结果然后通过一些回调传递回 parent.

function TestComp({ onChange, parentValue }) {
  const [value1, setValue1] = useState('value1');
  const [value2, setValue2] = useState('value2');

  // since mergedValues is used as dependency of the hook I need to 'memoize' it otherwise it gets 
  // recreated on each re-render and will cycle 
  const mergedValues = useMemo(() => ({
    val1: value1,
    val2: value2
  }), [value1, value2]);

  const updatedVals = useTestHook(mergedValues);

  useEffect(() => {
    onChange(updatedVals);
  }, [onChange, updatedVals]);

  return (
    <div>
      Hello
    </div>
  );
}

parent 可以对该值进行一些其他计算,结果 returns 返回给 child。

function App() {
  const [value, set] = useState('value1');

  return (
    <TestComp onChange={set} parentValue={value} />
  );
}

当 object 被用作某些效果的依赖项时,在 React 组件中处理 object 创建的正确方法是什么?可以使用 useMemo 钩子吗?

const mergedValues = useMemo(() => ({
    val1: value1,
    val2: value2
  }), [value1, value2]);

官方文档说“您可能依赖 useMemo 作为性能优化,而不是语义保证。” https://reactjs.org/docs/hooks-reference.html#usememo

另一种方法是将 hook 的 prop 从 object 更改为简单值,并在 hook 的 useEffect 中根据这些值创建 object,但这种方法不适合我。

What is the correct way to handle object creation in a react component when the object is used as a dependency of some effect? Can be the useMemo hook used for it?

是的,您可以使用 useMemo,但有一点需要注意。由于文档是这样说的:

You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to “forget” some previously memoized values and recalculate them on next rende

这意味着在某些情况下 useMemo 可以忘记其存储的值并仍然为您提供一个新对象,如果它使用该对象作为依赖项,这可能会使 useEffect 触发,这可能是不是你想要的。但是,如果您的 useEffect 过火不是问题,那么这就不是问题。

你也可以这样做,不需要 useMemo(假设 val1val2 是原语):

  useEffect(() => {
    set({
      val1: `${someOject.val1}_-`,
      val2: `${someOject.val2}_-`,
    })
  }, [someOject.val1, someOject.val2]);