37

I'm currently looking at the react doc's example for useEffect

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

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

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

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

My question is that we can easily make a handleClick function for the button. We don't have to use useEffect

const handleButtonClick = () =>{
setCount(count+1)
document.title = `You clicked ${count +1} times`
}

<button onClick={handleButtonClick}/>

So which way is considered good practice? Is it best to only use useEffect to trigger side effects that strictly couldn't be done along with the main effect(i.e when component receive new prop)

Veryfreebird
  • 405
  • 1
  • 4
  • 6

4 Answers4

35

The idea to use useEffect hook is to execute code that needs happens during lifecycle of the component instead of on specific user interactions or DOM events.

For instance, you wish to set a timer that executes a code when the component is rendered initially or as done in your initial example, the document title is updated when the component mounts, there is no user interaction associated here

useEffect is an alternative for lifecycle method in class components in a functional component. It can be used to execute actions when the component mounts, or certain prop or state updated for component as well as to execute code when the component is about to unmount

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • Can't we setup timer out side of react to cover the case when component is render initially? All subsequent render will be based on some event therefore event handler will cover all other cases. – Suraj Jain Aug 04 '22 at 02:12
11

Please refer below content for more clarity. You might have missed reading that after copying code from official document.

Example Using Hooks

What does useEffect do?

By using this Hook, you tell React that your component needs to do something after render. React will remember the function you passed (we’ll refer to it as our “effect”), and call it later after performing the DOM updates. In this effect, we set the document title, but we could also perform data fetching or call some other imperative API.

Why is useEffect called inside a component?

Placing useEffect inside the component lets us access the count state variable (or any props) right from the effect. We don’t need a special API to read it — it’s already in the function scope. Hooks embrace JavaScript closures and avoid introducing React-specific APIs where JavaScript already provides a solution.

Does useEffect run after every render?

Yes! By default, it runs both after the first render and after every update. (We will later talk about how to customize this.) Instead of thinking in terms of “mounting” and “updating”, you might find it easier to think that effects happen “after render”. React guarantees the DOM has been updated by the time it runs the effects.

Ankur
  • 496
  • 1
  • 6
  • 11
9

You showed two different examples,

handleButtonClick fires on Button 1 click, while useEffect fires on every state change state (according to the dependency array).

In the next example, you notice that useEffect will log on every button click (Button 1/2), and handleButtonClick will log only on Button 2 click.

import React, { useState, useEffect } from "react";

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

  useEffect(() => {
    console.log(`You rendered ${count} times`);
  }, [count]);

  const handleButtonClick = () => {
    setCount(count + 1);
    console.log(`You clicked ${count + 1} times`);
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Button 1</button>
      <button onClick={handleButtonClick}>Button 2</button>
    </div>
  );
}
Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
  • 1
    I understand.Now say I have another [count2, setcount2] state. I want to setCount2 everytime count change. Again there are two approach: add a setCount2 to every onClick(that already has setCount) or use useEffect to catch the count change, then use setCount2. Which approach should i take? – Veryfreebird Jul 12 '19 at 08:51
  • 1
    On the first approach, what will you do when you have 2000 buttons? You will go over all the buttons in your project? Or you can `useEffect` once. Consider the next points to define a "better approach": 1. Readability. 2. Maintenance. – Dennis Vash Jul 12 '19 at 08:53
  • Yeah but it will cause two render. One after setCount, one after the setCount2 in useEffect. If i group the two setCount and setCount2 in one handler function, the component should only render once. Am i over thinking on this? – Veryfreebird Jul 12 '19 at 08:56
  • "If I group the two setCount and setCount2 in one handler function, the component should only render once", it's not true, it will render twice, check it. – Dennis Vash Jul 12 '19 at 08:59
  • No, it should only render once. https://codesandbox.io/s/react-hooks-useeffect-hfvyt Check this. – Veryfreebird Jul 12 '19 at 09:05
  • Check the example... you are listening only to `count`, what with `dummy`? – Dennis Vash Jul 12 '19 at 09:07
  • Here you can check if it renders: https://codesandbox.io/s/react-hooks-useeffect-lmrp3 – Dennis Vash Jul 12 '19 at 09:10
  • https://codesandbox.io/s/react-hooks-useeffect-xkpck i removed the count. useEffect will fire on every render now – Veryfreebird Jul 12 '19 at 09:10
  • How does it prove that grouping them in a function renders once? Remember what you trying to prove. – Dennis Vash Jul 12 '19 at 09:13
  • I refer to the answer on this. https://stackoverflow.com/questions/55574438/using-multiple-sethook-makes-component-render-more-than-once In my example, i grouped the two setCount and setCount2. When i clicked the button, it only logged once. So the component only rendered once – Veryfreebird Jul 12 '19 at 09:17
  • And how it's different from `useEffect` you meant that useEffect will run twice while at the event handler will run once. – Dennis Vash Jul 12 '19 at 09:23
  • i meant that if i use setCount2 inside useEffect, it will cause the component to render twice. Once when setCount, once after when setCount2. If i group the two setCount to one handler function, they will only cause one render. – Veryfreebird Jul 12 '19 at 09:27
  • I think this discussion is pointless, if you change the state in `useFffect`, yes it will render twice. If you batch states, it will render once, does it really affects the performance? I don't think so, we can't go into to chat because you don't have enough points, furthermore this discussion is out of the scope of this question, please consider asking another. – Dennis Vash Jul 12 '19 at 09:38
  • Yeah i just wanted to know if it it really affects the performance or i'm just over thinking it. – Veryfreebird Jul 12 '19 at 09:40
  • No effect, react is damn fast. Always write readable and maintained code, handle performance on bottles necks, also welcome to StackOverflow! Please take the [Tour](https://stackoverflow.com/tour), and accept any answer that was helpful to you. – Dennis Vash Jul 12 '19 at 09:43
  • 1
    I see. So it's better to write clean code than saving few ms of render time – Veryfreebird Jul 12 '19 at 10:13
2

we use useEffects when we want to take advantage of components lifecycles. if you know about class components you would know about :

  • mounting
  • updating
  • unmounting

so, useEffects are a good alternative for them; it's lean and easier to use

erff-on
  • 303
  • 3
  • 9
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 28 '22 at 17:04