Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: Difference between side effect in component's function vs effect?

I'm trying to understand the practical difference between having a side effect in a component function, vs having it within an effect which has no dependency array passed in (and as such should fire on every render). From what I can observe, they both run at the same frequency. I realize that effects allow for cleanup at the proper time, but I'm simply curious about the scenario where cleanup is not a factor.

The following CodePen shows what I'm talking about.

https://codepen.io/benrhere/pen/GRyvXZZ

The important piece is:

function EffectVsFunctionQuestion() {
  const [count, setCount] = React.useState(0);

  React.useEffect(()=>{
    console.log("incremented within hook")
  });
  console.log("incremented within component function")
...
}
like image 935
BenjiFB Avatar asked Dec 06 '25 11:12

BenjiFB


2 Answers

Side-effects issued from the useEffect hook have the benefit of being triggered at most once per render cycle. The render cycle here means the "commit phase" when React has computed the next view and commits it to the DOM.

This should not be confused with what React calls the "render phase" when it renders out the component (and children and entire ReactTree) to compute what changed and needs to be committed to the DOM.

enter image description here

The entire function body of a React function component is the "render" function. As you can see in the diagram, any unintentional side-effects in the render or body will occur during the "render phase" which can can be paused, aborted, or restarted (i.e. run again) by React. Note that the "render phase" is to be pure and free from side-effects.

The "commit phase" the component can work with the DOM and run side-effects.

Why does this matter? How to tell the difference.?

React actually ships with a StrictMode component that helps you detect unexpected side-effects.

Detecting unexpected side effects

Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:

  • Class component constructor, render, and shouldComponentUpdate methods
  • Class component static getDerivedStateFromProps method
  • Function component bodies
  • State updater functions (the first argument to setState)
  • Functions passed to useState, useMemo, or useReducer

Here's an example sandbox demo that demonstrates the unexpected side effects.

Edit react-difference-between-side-effect-in-components-function-vs-effect

Note that the unexpected effect is doubled.

enter image description here

Code:

const externalValue1 = { count: 0 };
const externalValue2 = { count: 0 };

function EffectVsFunctionQuestion() {
  const [state, setState] = React.useState(0);

  React.useEffect(() => {
    externalValue1.count++;
    console.log("incremented within hook", externalValue1.count);
  });
  externalValue2.count++;
  console.log("incremented within component function", externalValue2.count);

  return (
    <button type="button" onClick={() => setState((c) => c + 1)}>
      Render
    </button>
  );
}
like image 125
Drew Reese Avatar answered Dec 09 '25 01:12

Drew Reese


Essentially the useEffect hook ensures that code will not run until the DOM is mounted/updated. If you run code outside of it, it can be called before the DOM renders, which could lead to issues. It won't block content from rendering, since it's called after render. It's the equivalent of several of the previous class based lifecycle methods (ComponentDidMount, etc.). Docs

like image 42
Ross Avatar answered Dec 08 '25 23:12

Ross



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!