Home > database >  Is it OK to use two or more functions for useEffect?
Is it OK to use two or more functions for useEffect?

Time:10-01

Recently, I was reading RectJS documentation and I've seen that useEffect function takes another function as argument. Example from documentation:

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

Can I some how select function that called after the render? And is it fine to do this? Example, what I mean:

  useEffect(this.state.count % 2 == 1 ? 
     () => {
       document.title = `You clicked ${count} times (ODD)`;
     } : 
     () => {
       document.title = `You clicked ${count} times(EVEN)`;
     }
  );

It probably not the best example. It could be done without extra function, but it is just an example.

PS. This is just teoretical question and I don't know if it practicaly usable (or possible). I'm new to React. I hope somebody will explain this to me.

CodePudding user response:

Yes, it is completely okay.

According to the docs - Use Multiple Effects to Separate Concerns:

Just like you can use the State Hook more than once, you can also use several effects. This lets us separate unrelated logic into different effects.

React will apply every effect used by the component, in the order they were specified.

CodePudding user response:

useEffect has two parameters, a function and an array of dependencies. Whenever any of the items in the dependency array changes, the function as the first parameter passed to the useEffect is called.

For your particular example, it can be demonstrated as follows:

export default function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    if (count % 2 === 0) {
      console.log("COUNT IS EVEN");
    } else {
      console.log("COUNT IS ODD");
    }
  }, [count]);

  return (
    <div className="App">
      <h1>Count: {count}</h1>
      <button onClick={() => setCount((c) => c   1)}>Increment</button>
    </div>
  );
}

Notice [count] as the second param of useEffect, whenever count changes, our function runs and logs whether the value of count is odd or even.

For separate use cases, it's advised to separate your logic out into separate useEffect hooks. For example, consider you have another value for which you want to run your side-effects, you can do so by creating another hook and passing the dependency array.

There are some other nuances to useEffect such as what happens if you don't pass a dependency array to the hook or what if you pass an empty array as the dependency. I would encourage you to look into on your own.

CodePudding user response:

Instead of dynamically choosing what function to pass useEffect it would be much cleaner to instead always pass the same function, and in that function choose what to do.

Choosing what to do could be calling two different functions, or just the title setting itself, thats up to you, but I wouldn't try to do your conditional logic like it is currently.

Example of both your version and my suggestion:

As you can see, they are functionally the same. But I see absolutely no reason to opt for ExampleA.

const { useState, useEffect } = React;

function ExampleA() {
  const [count, setCount] = useState(0);
  
  useEffect(count % 2 == 1 ? 
     () => {
       console.log(`You clicked ${count} times (ODD)`);
     } : 
     () => {
       console.log(`You clicked ${count} times(EVEN)`);
     }
  );
  
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count   1)}>
        Click me
      </button>
    </div>
  );
}

function ExampleB() {
  const [count, setCount] = useState(0);
  
  function even() {
    console.log(`You clicked ${count} times (EVEN)`);
  }

  function odd() {
    console.log(`You clicked ${count} times (ODD)`);
  }

  useEffect(() => {
    if (count % 2 == 1) {
      odd();
    } else {
      even();
    }
  });
  
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count   1)}>
        Click me
      </button>
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>Your option</h1>
      <ExampleA />
      <h1>My Suggestion</h1>
      <ExampleB />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

  • Related