Function inside functional component in React hook

2020-06-09 11:54发布

Need suggestion on having function within a functional component in react Hooks.

As far as I researched, many are saying it is bad practice because it creates nested/inner function every time we call re-render. After doing some analysis,

I found we can use onClick={handleClick.bind(null, props)} on the element and place the function outside the functional component.

Example:

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

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

Please advise if there is any alternative way.

Thanks in advance.

4条回答
ゆ 、 Hurt°
2楼-- · 2020-06-09 12:20

You can use useCallback feature :

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

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

useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).

For further details visit their reference link: React useCallback


The old way has two options too.

First solution: To pass the your handleClick function to your functional component.

const HelloWorld = (props) => {

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

Second solution: To define your function outside of your functional component.

查看更多
叛逆
3楼-- · 2020-06-09 12:23

many are saying it is bad practice because it creates nested/inner function every time we call re-render

No, inner functions / closures are so common, there is no problem with them. The engine can heavily optimize those.

The point here is that you pass the function as a prop to the child component. And as the function was "recreated", it does not equal the previous function passed, annd thus the child does rerender (and that's whats bad for performance).

You can resolve that with useCallback, which memoizes the function reference.

查看更多
一夜七次
4楼-- · 2020-06-09 12:34

As per React Documentation (ending part),

The problem with latter syntax is that a different callback is created each time the LoggingButton renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering. We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.

Class field syntax:

class LoggingButton extends React.Component {
  // This syntax ensures `this` is bound within handleClick.
  // Warning: this is *experimental* syntax.
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

arrow function in the callback syntax:

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // This syntax ensures `this` is bound within handleClick
    return (
      <button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }
}
查看更多
Juvenile、少年°
5楼-- · 2020-06-09 12:36

Don't worry about it

Don't worry about creating new functions on each render. Only in edge cases does that impede your performance. Setting onClick handlers are not one of those, so just create a new function on each render.

However, when you need to make sure you use the same function every time, you can use useCallaback

Why not use useCallback for onClick

Here is a reason why you shouldn't bother with useCallback for onClick handlers (and most other event handlers).

Consider the following code snippets, one without useCallback:

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

and one with useCallback:

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

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

The only difference in the latter is that React doen's have to change the onClick on your button if props.foo remains the same. Changing the callback is a very cheap operation, and it's not at all worth complicating your code for the theoretical performance improvement it gives.

Also, it's worth noting that a new function is still created on every render even when you use useCallback, but useCallback will return the old one as long as the dependencies passed as the second argument are unchanged.

Why ever use useCallback

The point of using useCallback is that if you compare two functions with reference equality, fn === fn2 is true only if fn and fn2 point to the same function in memory. It doesn't matter if the functions do the same.

Thus, if you have memoisation or otherwise only run code when the function changes, it can be useful to use useCallback to use the same function again.

As an example, React hooks compare old and new dependencies, probably using Object.is.

Another example is React.PureComponent, which will only re-render when props or state have changed. This can be useful for components that use a lot of resources to render. Passing e.g. a new onClick to a PureComponent on each render will cause it to re-render every time.

查看更多
登录 后发表回答