How to manage side effects in React?

React is a UI library that represents the view of an app as a function of state. This means whenever the state changes, React will run our component function with the intention of updating the view. In order to do so, React expects our component to be a pure function, but we know it's not that simple and there are use cases when the state of our app depends on side effects.

Side effects are the external events or systems on which the state of our app depends in order to refresh the view. API requests, DOM manipulation, and browser APIs like setTimeout and setInterval are some common examples of side effects.

Although React is quite efficient in managing the state of our app, in case of side effects, we specifically have to take care of how and when to tell React for a state change.

Let's see an example, but just a request for this example forget that you know anything about side effects and then see how someone without knowing side effects will handle them.

Now let's say we want to save the last drink user tried to local storage so that he can resume from where he left off.

Your first thought would be to save it in localStorage, which is correct. Now let's say you are thinking most vaguely and do not care where to place this effect and end up placing it like this:

This will get the job done of saving the value of the selected drink's index, but we are breaking the rule of pure rendering here. React should not run into any side effects while rendering. So the right way to handle this is, to put it inside the event handler (handleNextDrink) invoking the event. You must be thinking this is a lame example and you might already know this. But hey, we are assuming the lamest kind of solution to be given here.

Now, let's see an example where we need to use a browser API and change our state accordingly, but this time there is no event handler involved, instead we need to update our view based on the result we get from the browser API.

This is where React's useEffect helps us in managing effects.

Here, we get the current battery level of the system and if it is not equal to the previous one, then we update the value and re-render the app.

One thing to notice here is, that on the initial render, React first renders and then gets's battery level in useEffect, but only updates the state if it is not equal to the previous state. Here, on the initial render, we have batteryLevel as 0 as our default value of the state. So when React runs useEffect for the first time, it will fetch the system's battery level and then set the batteryLevel to the value returned and this will cause a re-render. This will again invoke useEffect but this time it won't invoke state update and thus effect will stop here.

If you have prior knowledge of useEffect, you must be thinking shouldn't it cause an error because we do not pass a dependency array here, which is mentioned almost everywhere about how to use useEffects.

But even though here useEffect runs on every re-render, we are not running into an issue because the battery level does not change often and we have made sure to only update the state when the level changes, so this avoids us running into an infinite loop of re-render. But still, this is not the right way to write useEffects.

Since here we only want to check batteryLevel on the initial render, we can pass an empty array to our useEffect's dependency array, which is the second argument it accepts.

Dependency array makes sure to provide everything useEffect needs to update the view.

In conclusion, it all boils down to 3 main things to keep in mind when managing effects:

  1. React component should always render without running into any side effect.

  2. If a side effect is triggered by an event, it should be put inside the event handler.

  3. If a side effect is synchronizing our component with an external system, then it should be put inside useEffect.

These rules can help you manage and think about handling effects efficiently.

That's all folks!! I hope you learned something from this and it turned out to be worth your time.

Please appreciate this by leaving a like. Feel free to share your valuable comments and feedback.

Thanks for reading!!

Did you find this article valuable?

Support Sakshi Chaudhary's Blog by becoming a sponsor. Any amount is appreciated!