reactjs 使用参数进行回调

jjhzyzn0  于 2022-11-29  发布在  React
关注(0)|答案(1)|浏览(101)

使用React的useCallback钩子本质上只是一个专门用于函数的useMemo的 Package 器,以避免在组件的props中不断创建新的函数示例。我的问题来自于何时需要将argumed传递给从memorization创建的回调。
例如,像这样创建的回调...

const Button: React.FunctionComponent = props => {
    const onClick = React.useCallback(() => alert('Clicked!'), [])
    return <button onClick={onClick}>{props.children}</button>
}

是一个记忆回调的简单例子,不需要传递任何外部值来完成它的工作。但是,如果我想为React.Dipatch<React.SetStateAction>函数类型创建一个通用的记忆回调,那么它需要参数...例如:

const Button: React.FunctionComponent = props => {
    const [loading, setLoading] = React.useState(false)
    const genericSetLoadingCb = React.useCallback((x: boolean) => () => setLoading(x), [])

    return <button onClick={genericSetLoadingCb(!loading)}>{props.children}</button>
}

在我的脑海里,这似乎是完全一样的做以下...

const Button: React.FunctionComponent = props => {
    const [loading, setLoading] = React.useState(false)
    return <button onClick={() => setLoading(!loading)}>{props.children}</button>
}

这将使记忆该函数的目的失败,因为由于genericSetLoadingCb(false)也将仅在每次呈现时返回新函数,所以它仍将在每次呈现时创建新函数。
这种理解是正确的吗?或者说,用论证描述的模式仍然保留了记忆化的好处吗?

dgiusagp

dgiusagp1#

我将用一个稍微不同的用例来回答这个问题,但它仍然包含对您的问题的回答。

动机和问题陈述

让我们考虑以下高阶函数genericCb(类似于genericSetLoadingCb):

const genericCb = React.useCallback(
    (param) => (e) => setState({ ...state, [param]: e.target.value }),
    []
  );

假设我们在以下情况下使用它,其中Input是使用React.memo创建的记忆组件

<Input value={state.firstName} onChange={genericCb('firstName')} />

由于Input是记忆组件,我们可能希望**genericCb('firstName')生成的**函数在重新渲染时保持不变,这样记忆组件就不会不必要地重新渲染。下面我们将看到如何实现这一点。

溶液

现在,我们构建上述genericCb的方法是确保它在渲染中保持相同(由于使用了useCallback)。
但是,每次调用genericCb创建新函数时,如下所示:

genericCb("firstName")

返回的函数在每个渲染上仍然是不同的。为了确保返回的函数对于某些输入是记忆的,你应该额外使用一些记忆方法:

import memoize from "fast-memoize";
  ....

  const genericCb = React.useCallback(
    memoize((param) => (e) => setState({ ...state, [param]: e.target.value })),
    []
  );

现在,如果您调用genericCb("firstName")来生成一个函数,它将在每次渲染时返回相同的函数,前提是"firstName"也保持不变

备注

正如在上面的注解中指出的,使用useCallback的解决方案似乎会产生警告(尽管在我的项目中没有):
React Hook useCallback收到一个依赖关系未知的函数。请改为传递内联函数
看起来警告是存在的,因为我们没有传递内联函数给useCallback。我找到的基于this github线程消除这个警告的解决方案是使用useMemo来模拟useCallback,如下所示:

// Use this; this doesn't produce the warning anymore  
const genericCb = React.useMemo(
    () =>
      memoize(
        (param) => (e) => setState({ ...state, [param]: e.target.value })
      ),
    []
  );

简单地使用memoize而不使用useCallback(或者更新中的useMemo)是不起作用的,因为在下一次渲染时,它将从fresh调用memoize,如下所示:

let memoized = memoize(fn)
 
memoized('foo', 3, 'bar')
memoized('foo', 3, 'bar') // cache hit

memoized = memoize(fn); // without useCallback (or useMemo) this would happen on next render 

// Now the previous cache is lost

相关问题