I have a Button component that should submit a form (provided via props) to the server. Before the button is clicked the form is mutated very often, so when connecting the Button to it, the Button re-renders very oftern as well.

Before hooks, I solved this problem by providing a shouldComponentUpdate that returns false but updates this.form, so that the instance variable is always up to date, even if the component is not re-rendering:

class ButtonContainer extends React.Component {

  form = null;

  shouldComponentUpdate(nextProps, nextState) {
    // prevent re-render but update variable
    this.form = nextProps.form;
    return false
  }

  submitForm = () => {
    console.log(this.form);
    // ...
  }

  render() {
    return <button onClick={this.submitForm}>Submit</button>
  }
}

Can we achieve the same with functional components?

3 Answers

0
Andrii Golubenko On

If you want your component to be updated only when props change, you should use React.memo for functional components. And for class components, it will better to use extending from React.PureComponent. With PureComponent you don't need to implement shouldComponentUpdate

0
Bill Metcalf On

It's hard to tell exactly what you are wanting to do without a demo, but you should look into the useEffect hook, and namely the second value you can pass to it to decide when it should (re)run https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect

0
Murtaza Hussain On

React memo – which is one of React’s top level APIs – can be used for React Function Components to prevent a rerender when the incoming props of this component haven’t changed

For more details please visit here https://reactjs.org/docs/react-api.html#reactmemo

Here is a example of using memo in which the Count component doesn’t update anymore when the user types something into the input field. Only the App component rerenders.

import React, { useState, memo } from 'react';

const App = () => {
  const [greeting, setGreeting] = useState('Hello React!');
  const [count, setCount] = useState(0);

  const handleIncrement = () =>
    setCount(currentCount => currentCount + 1);

  const handleDecrement = () =>
    setCount(currentCount => currentCount - 1);

  const handleChange = event => setGreeting(event.target.value);

  return (
    <div>
      <input type="text" onChange={handleChange} />
      <Count count={count} />
      <button type="button" onClick={handleIncrement}>
        Increment
      </button>
      <button type="button" onClick={handleDecrement}>
        Decrement
      </button>
    </div>
  );
};

const Count = memo(({ count }) => {
  console.log('Does it (re)render?');
  return <h1>{count}</h1>;
});

export default App;