React Hooks,如何防止不必要的重新渲染。

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

React Hooks, how to prevent unnecessary rerendering

问题

我有一个从另一个钩子获取数据的钩子

const useIsAdult = () => {
  const data = useFormData();

  return data.age > 18;
}

这个钩子只返回true或false,但是useFormData不断更新。每次useFormData重新运行时,它会重新渲染我的组件。我只希望在useIsAdult的结果发生变化时重新渲染我的组件。

我知道这显然可以通过在react-redux中实现一些逻辑并使用它们的useSelector来防止渲染来解决,但我正在寻找一个更基本的解决方案,如果有的话。

在你提到memo之前,请仔细阅读问题。返回值是一个布尔值,在这里使用memo没有任何意义。

英文:

I have a hook that gets data from another hook

const useIsAdult = () => {
  const data = useFormData();

  return data.age > 18;
}

This hook returns true or false only, however the useFormData is constantly being updated. Everytime useFormData reruns, it will rerender my component. I only want my component to rerender if the result of useIsAdult changes.

I know this can obviously be solved by implementing some logic via react-redux and using their useSelector to prevent rendering, but I'm looking for a more basic solution if there is any.

Before you say useMemo, please read question carefully. The return value is a boolean, memo here doesnt make any sense.

答案1

得分: 1

即使在使用useMemo返回值的情况下,useIsAdult父组件仍然会重新渲染。这个问题是我很少使用其他依赖钩子创建自定义钩子的原因。这将导致不断的重新渲染。

在这里,我尝试说明useMemo不起作用。对于组件来说,使用useMemo是错误的方式。对于组件,我们有React.memo

const MyComponent = memo(({ isAdult }: { isAdult: boolean }) => {
  console.log("renderMy");
  return <h1>Hello CodeSandbox</h1>;
});

memo将有助于防止MyComponent的重新渲染。但是父组件仍然会重新渲染。

CodeSandbox链接

如果可以修改useFormData,也许可以使用useRef。您可以将数据存储在useRef中,但它不会触发重新渲染。

类似于这样,但在useFormData中实现:

const useIsAdult = () => {
  const data = useFormData();
  const prevIsAdultRef = useRef();
  const isAdult = useMemo(() => data.age > 18, [data]);

  if (prevIsAdultRef.current === isAdult) {
    return prevIsAdultRef.current;
  }

  prevIsAdultRef.current = isAdult;
  return isAdult;
};

我不知道useFormData是如何工作的,所以您可以尝试自己使用useRef

如果useFormData经常获取数据,而您无法管理这种情况,您可以使用防抖或节流来减少更新次数。

英文:

Even with returned useMemo in useIsAdult parent component will be rerendered. This problem is reason why I rarely create custom hooks with other hooks dependency. It will be rerender hell.

There I tried to show that useMemo doesnt work. And using useMemo for components its wrong way. For components we have React.memo.

const MyComponent = memo(({ isAdult }: { isAdult: boolean }) =&gt; {
  console.log(&quot;renderMy&quot;);
  return &lt;h1&gt;Hello CodeSandbox&lt;/h1&gt;;
});

And memo will help to prevent rendering of MyComponent. But parent component still render.

https://codesandbox.io/s/interesting-lumiere-xbt4gg?file=/src/App.tsx

If you can modify useFormData maybe useRef can help. You can store data in useRef but it doesnt trigger render.

Something like this but in useFormData:

onst useIsAdult = () =&gt; {
  const data = useFormData();
  const prevIsAdultRef = useRef();
  const isAdult = useMemo(() =&gt; data.age &gt; 18, [data]);

  if (prevIsAdultRef.current === isAdult) {
    return prevIsAdultRef.current;
  }

  prevIsAdultRef.current = isAdult;
  return isAdult;
};

I dont know how useFormData works, then you can try it self with useRef.

And if useFormData gets data very often and you cant manage this, you can use debounce or throttle to reduce number of updates

答案2

得分: -1

**Memoize钩子**

```jsx
const useIsAdult = () => {
  const data = useFormData();
  return useMemo(() => data.age > 18, [data.age]);
}

在这里,useMemo 允许你缓存计算或多次渲染,通过“记住”先前的计算。因此,如果依赖项 (data.age) 没有改变,它将简单地重用它上次返回的值,也就是缓存的值。

Memoize组件表达式

useMemo 也可以用于记忆组件表达式,如下所示:

const renderAge = useMemo(() => <MyAge age={data.age} />, [data.age]);
return {renderAge}

在这里,只有当 data.age 的值发生变化时,MyAge 才会重新渲染。


<details>
<summary>英文:</summary>

**Memoize hook**

    const useIsAdult = () =&gt; {
      const data = useFormData();
      return useMemo(() =&gt; data.age &gt; 18, [data.age]);
    }


Here, `useMemo` will let you cache the calculation or multiple renderes, by &quot;remembering&quot; previous computation. So, if the dependency (data.age) doesn&#39;t change then it will use simply reuse the last value it returned, the cached one.

**Memoize component expression**

`useMemo` can also be used to memoize component expressions like this: -


    const renderAge = useMemo(() =&gt; &lt;MyAge age={data.age} /&gt;, [data.age]);
    return {renderAge}

Here, `MyAge` will only re-render if the value of data.age changes.


</details>



huangapple
  • 本文由 发表于 2023年2月19日 19:47:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75499912.html
匿名

发表评论

匿名网友

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

确定