10

In the React docs I see this piece of code:

function Example() {
  const [count, setCount] = useState(0);

  //THE SUBJECT OF MY QUESTION:
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

So, my question is why not change the document.title or any other DOM without using useEffect, like this:

function Example() {
  const [count, setCount] = useState(0);

  //THE SUBJECT OF MY QUESTION:
  document.title = `You clicked ${count} times`;

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

I know that when sending requests for example, it is asynchronous and we need to do it in useEffect. But DOM manipulation isn't asynchronous and it takes relatively 0 time, why do we then still have to use useEffect hook?

Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
thewebmasterp
  • 115
  • 1
  • 6
  • 1
    useEffect without second params ([]) render every time state change so in my oponion it is the same – Anh Tuan May 28 '20 at 09:48

3 Answers3

5

Its almost the same, see my related answer, useEffect in-depth.

The difference is a notable "gotcha", useEffect callback executed after the render phase.

const App = () => {
  useEffect(() => {
    console.log("executed after render phase");
  });

  console.log("executed at render phase");

  return <></>;
};

Will result:

executed at render phase
executed after render phase

Edit useEffect execute phase

Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
5

You better keep DOM manipulations and other side effects inside useEffect.

useEffect(() => {
    document.title = `You clicked ${count} times`;
}, [count]); // set your dependencies

Reason is: This approach is compliant with React Strict Mode and upcoming Concurrent Mode.

What Concurrent mode is:

[...] React may invoke render phase lifecycles more than once before committing, or it may invoke them without committing at all (because of an error or a higher priority interruption).

In your case, the document.title assignment might be repeated multiple times or React might even decide to abort the whole commit. In general, this can lead to inconsistencies:

Because the above methods might be called more than once, it’s important that they do not contain side-effects. Ignoring this rule can lead to a variety of problems, including memory leaks and invalid application state. (docs)

ford04
  • 66,267
  • 20
  • 199
  • 171
2

It's important to know how useEffect works.

Here's some clarity.

useEffect(() => {
  // this runs when the component mounts

  return () => {
    // This runs when the component unmounts (not useful for you right now)
  }
}, []); // You were missing the second argument (dependencies array)

Regarding the dependencies array. Putting values in there will cause your effect to run again when that value changes, which is very useful for your need.

What you should do is the following:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]);

This will update document.title whenever count changes.

I generally recommend making use of useEffect for these kinds of situations over not using it simple because it will take all the life-cycle processes into account.

TLDR: It should perform better.

Barry Michael Doyle
  • 9,333
  • 30
  • 83
  • 143
  • He asked about the example in docs: https://reactjs.org/docs/hooks-effect.html – Dennis Vash May 28 '20 at 10:08
  • I see that, I still stand by my answer. Not making use of `useEffect` means that the `document.title` will get reset everytime anything else changes. I believe the dependency array is a very important part of the `useEffect` hook that shouldn't be ignored. – Barry Michael Doyle May 28 '20 at 10:12
  • It is not ignored... Its a beginner guide which explains it when you progress reading, your answer is at the end of the page... https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects – Dennis Vash May 28 '20 at 10:15