首页 > 解决方案 > React.useCallback() 用于链式匿名函数

问题描述

通常,为了将onChange回调函数传递给组件,您需要执行以下操作:

const handleChange = (e) => {
  console.log(e.target.value)
}

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

如果您不希望Component每次主组件都渲染,则必须将其包装在React.useCallback()挂钩中,如下所示:

const handleChange = React.useCallback((e) => {
  console.log(e.target.value)
}, [])

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

如果此输入是在基于列表的 for 循环中生成的,您希望回调了解更改的来源。传递信息的最常见方法是链接 lambda,如下所示:

const fields = ['field1', 'field2', 'field3']

const handleChange = (fieldName) => (e) => {
  console.log(`${fieldName}: `, e.target.value)
}

return (
  <>
    {fields.map((x) => <Component onChange={handleChange(x)} />}
  </>
)

React.useCallback()但是在这种情况下,在使用钩子将整个上下文保存在函数中的同时记住外部和内部 lambdas 是不可能的。

在大多数情况下,我可以控制组件并更改回调以包含所需的数据,但通常会发生组件来自库(例如 Material-UI),因此无法修改。

用 React Hooks 以什么方式可以完全记住这个回调?

标签: javascriptreactjslambdareact-hooksmemoization

解决方案


您可以为每个元素生成事件处理程序,并记住事件处理程序数组。创建元素时,通过它的索引获取相关的事件处理程序:

const { memo, useMemo } = React

const Demo = ({ fields }) => {
  const handlers = useMemo(() => 
    fields.map(fieldName => e => {
      console.log(`${fieldName}: `, e.target.value)
    })
  , [fields])

  return (
    <div>
      {
        fields.map(
          (fieldName, i) => (
            <input key={fieldName} onChange={handlers[i]} />
          ))
      }
    </div>
  )
}

const fields = ['field1', 'field2', 'field3']

ReactDOM.render(
  <Demo fields={fields} />,
  root
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>


推荐阅读