URL: https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects

React 16.8.0 with Hooks was released today. A big deal. Executive summary; components as functions is all the rage now.

What used to be this:


class MyComponent extends React.Component {
  ...

  componentDidMount() {
    ...
  }
  componentDidUpdate() {
    ...
  }

  render() { STUFF }
}

...is now this:


function MyComponent() {
  ...

  React.useEffect(() => {
    ...
  })

  return STUFF
}

Inside the useEffect "side-effect callback" you can actually update state. But if you do, and this is no different that old React.Component.componentDidUpdate, it will re-run the side-effect callback. Here's a simple way to cause an infinite recursion:


// DON'T DO THIS

function MyComponent() {
  const [counter, setCounter] = React.useState(0);

  React.useEffect(() => {
    setCounter(counter + 1);
  })

  return <p>Forever!</p>
}

The trick is to pass a second argument to React.useEffect that is a list of states to exclusively run on.

Here's how to fix the example above:


function MyComponent() {
  const [counter, setCounter] = React.useState(0);
  const [times, setTimes] = React.useState(0);

  React.useEffect(
    () => {
      if (times % 3 === 0) {
        setCounter(counter + 1);
      }
    },
    [times]  // <--- THIS RIGHT HERE IS THE KEY!
  );

  return (
    <div>
      <p>
        Divisible by 3: {counter}
        <br />
        Times: {times}
      </p>
      <button type="button" onClick={e => setTimes(times + 1)}>
        +1
      </button>
    </div>
  );
}

You can see it in this demo.

Note, this isn't just about avoiding infinite recursion. It can also be used to fit your business logic and/or an optimization to avoid executing the effect too often.

Comments

Jake

...this is the entire article?

Your email will never ever be published.

Previous:
Displaying fetch() errors and unwanted responses in React February 6, 2019 Web development, React, JavaScript
Next:
Optimize DOM selector lookups by pre-warming by selectors' parents February 11, 2019 Web development, Node, Web Performance, JavaScript
Related by category:
You don't need a context or state manager for TanStack Query in scattered React components January 2, 2026 JavaScript, React
Always run biome migrate after upgrading biome August 16, 2025 JavaScript
Video to Screenshots app June 21, 2025 JavaScript, React
gg2 has a web page now January 5, 2026 JavaScript
Related by keyword:
You don't need a context or state manager for TanStack Query in scattered React components January 2, 2026 React, JavaScript, TypeScript
React.memo instead of React.PureComponent November 2, 2018 React, JavaScript
Git + Twitter = Friedcode April 22, 2009 Python, Linux