React hooks 中的函数组件中的函数 - 性能

IT技术 javascript reactjs react-hooks
2021-05-10 11:29:02

需要关于在react中的功能组件中具有功能的建议Hooks

据我研究,许多人说这是不好的做法,因为每次我们调用重新渲染时它都会创建嵌套/内部函数。经过一番分析,

我发现我们可以onClick={handleClick.bind(null, props)}在元素上使用并将函数放在函数组件之外。

例子:

const HelloWorld = () => {
  function handleClick = (event) => {
    console.log(event.target.value);
  }

  return() {
    <>
        <input type="text" onChange={handleClick}/>
    </>
  }
}

请告知是否有任何替代方法。

提前致谢。

4个回答

别担心

不要担心在每个渲染上创建新函数。只有在边缘情况下才会妨碍您的表现。设置onClick处理程序不是其中之一,所以只需在每个渲染上创建一个新函数。

但是,当您需要确保每次都使用相同的函数时,可以使用useCallback

为什么不useCallback用于onClick

这是您不应该useCallbackonClick处理程序(和大多数其他事件处理程序)烦恼的原因

考虑以下代码片段,其中一个没有 useCallback:

function Comp(props) {
  return <button onClick={() => console.log("clicked", props.foo)}>Text</Button>
}

和 useCallback 之一:

function Comp(props) {
  const onClick = useCallback(() => {
    console.log("clicked", props.foo)
  }, [props.foo])

  return <button onClick={onClick}>Text</Button>
}

后者的唯一区别是 React 必须更改onClick按钮上的props.foo保持不变。 更改回调是一个非常便宜的操作,为了理论上的性能改进,它根本不值得让您的代码复杂化。

此外,值得注意的是, 即使您使用每次渲染仍会创建一个新函数useCallback,但useCallback只要作为第二个参数传递的依赖项不变就会返回旧函数。

为什么一直用 useCallback

使用的要点useCallback是,如果将两个函数与引用相等进行比较,fn === fn2则仅当fnfn2指向内存中的同一函数时才为真功能是否相同并不重要

因此,如果您有记忆或仅在函数更改时运行代码,useCallback再次使用相同的函数会很有用

例如,React 钩子比较旧的和新的依赖项,可能使用Object.is

另一个例子是React.PureComponent,它只会在 props 或 state 改变时重新渲染。这对于使用大量资源进行渲染的组件很有用。例如onClick,在每次渲染时将new 传递给 PureComponent 将导致它每次重新渲染。

许多人说这是不好的做法,因为每次我们调用重新渲染时它都会创建嵌套/内部函数

不,内部函数/闭包是如此常见,它们没有问题。引擎可以对这些进行大量优化。

这里的重点是您将函数作为props传递给子组件由于函数是“重新创建”的,它不等于传递的前一个函数,因此子函数会重新渲染(这对性能不利)。

您可以使用 来解决该问题useCallback,它会记住函数引用。

useCallback

您可以使用useCallback功能:

const HelloWorld = ({ dispatch }) => {
  const handleClick = useCallback((event) => {
    dispatch(() => {console.log(event.target.value)});
  })

  return() {
    <>
        <input type="name" onChange={handleClick}/>
    </>
  }
}

useCallback将返回回调的记忆版本,该版本仅在依赖项之一发生更改时才会更改。这在将回调传递给依赖引用相等的优化子组件时很有用,以防止不必要的渲染(例如 shouldComponentUpdate)。

有关更多详细信息,请访问 react 文档参考:React useCallback


旧解决方案

第一个解决方案:将您的handleClick功能传递给您的功能组件。

const HelloWorld = (props) => {

  return() {
    <>
        <input type="name" onChange={props.handleClick}/>
    </>
  }
}

第二种解决方案:在功能组件之外定义您的功能。

在此处输入图片说明

有趣的问题,我和我的同事对此有些担心,所以我做了一个测试。

我创建了 1 个带钩子的组件和 1 个带类的组件,在那里放置了一些函数,然后将其渲染 1000 倍。

带有类的组件如下所示:

export class ComponentClass extends React.PureComponent {
  click1 = () => {
    return console.log("just a log");
  };

  render() {
    return (
      <>
        <span onClick={this.click1}>1</span>
      </>
    );
  }
}

带钩子的组件如下所示:

export const ComponentHook = React.memo((props) => {
  const click1 = () => {
    return console.log("just a log");
  };

  return (
    <>
      <span onClick={click1}>1</span>
    </>
  );
});

我在组件中添加了更多的点击处理程序,然后渲染它们大约 1000 次,类更快,因为它没有定义每次渲染的函数,如果增加定义的函数数量,那么差异会更大:

这是一个代码沙箱,因此您可以测试性能 Class vs Hooks :https ://codesandbox.io/s/hooks-vs-class-forked-erdpb