使用 useCallback 钩子的正确方法是什么?

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

What is the right way to use the useCallback hook?

问题

我有一个自定义输入组件,如下所示:

import React, { useState, useCallback } from 'react'

function MyCustomInput ({value: initialValue = '0'}) {
  const [value, setValue] = useState(initialValue)

  const handleChange = useCallback(
    value => {
     setValue(value)
    },
    [setValue]
  )

  return (
    <SomeInputComponent onChange={handleChange}/>
  )
}

React中的useCallback实现在文档中说:

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b]
)

根据文档的实现,正确的方式应该是:

const handleChange = useCallback(
   value => {
     setValue(value)
   },
   [value] // 而不是[setValue]
 )

但是这样做会使useCallback的使用变得毫无意义,因为handleChange每次value状态更新时都会获得一个新的函数引用,这将导致不必要的重新渲染<SomeInputComponent>组件。我的实现是否有错误?
1: https://reactjs.org/docs/hooks-reference.html#usecallback

英文:

I have an custom input component, like so:

import React, { useState, useCallback } from &#39;react&#39;

function MyCustomInput ({value: initialValue = &#39;0&#39;}) {
  const [value, setValue] = useState(initialValue)

  const handleChange = useCallback(
    value =&gt; {
     setValue(value)
    },
    [setValue]
  )

  return (
    &lt;SomeInputComponent onChange={handleChange}/&gt;
  )
}

The useCallback implementation in React doc says:

const memoizedCallback = useCallback(
  () =&gt; {
    doSomething(a, b);
  },
  [a, b]
)

Now as per the doc implementation, the correct way should be:

const handleChange = useCallback(
   value =&gt; {
     setValue(value)
   },
   [value] // And not, [setValue]
 )

But this would make the use of useCallback worthless as handleChange would start to get a new func reference each time the value state updates which would lead to unnecessary rerender of my &lt;SomeInputComponent&gt; component. Is my implementation incorrect?
1: https://reactjs.org/docs/hooks-reference.html#usecallback

答案1

得分: 1

你应该包括创建函数所需的所有内容,value 在调用函数时作为普通参数传递。

在这种情况下,构建函数所需的唯一依赖项是 setValue

const handleChange = useCallback(
  value => {
    setValue(value)
  }, [setValue]
)

然而,由于setStatedispatch(来自useReducer)和useRef被认为是静态的,你可以从依赖项列表中省略它们。exhaustive-deps规则有一个名为isDefinitelyStaticDependency(reference)的函数,它查找并“批准”这些函数为静态函数。因此,你的代码应该是这样的:

const handleChange = useCallback(
  value => {
    setValue(value)
  }, []
)
英文:

You should include everything that is needed to create the function, the value is passed as a normal parameter when the function is called.

The only dependency needed to build the function in this case is setValue:

const handleChange = useCallback(
  value =&gt; {
    setValue(value)
  }, [setValue]
)

However, since setState, dispatch (from useReducer), and useRef are known to be static, you can omit them from the list of dependencies. The exhaustive-deps rule has a function isDefinitelyStaticDependency(reference) that looks for and "approves" this functions as static. So your code should be:

const handleChange = useCallback(
  value =&gt; {
    setValue(value)
  }, []
)

huangapple
  • 本文由 发表于 2020年1月6日 18:21:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/59610334.html
匿名

发表评论

匿名网友

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

确定