What we gonna learn:
What are side Effects?
Whatโs the purpose of side Effects in React?
How to declare useEffect in a component?
What the purpose of clean up function?
Let's explore and understand the "why" behind each of these questions. Happy reading! If you have any doubts or questions, feel free to leave a comment.
what are side Effects?
We all know that React's primary purpose is to render the UI and respond to user interactions, but can't we expect React to do more? Like fetching data from APIs and synchronizing with third-party libraries.
Before we start discussing the finer details, let's revisit something we're already familiar with:
The code we write within each component is directly tied to what appears on the screen. We can refer to this as โtop-level codeโ, responsible for computing the JSX code based on all the available data, including state, props, etc., at that point in time, in order to render it on the screen.
Top level code is indeed a form of rendering code and itโs apparent why we call it so. However, rendering code should always remain pure, free from any side effects, like math formula, where same inputs always yield the same output.
Code that changes programs state is side effects
Letโs not overlook event handlers within our components. The handler code executes whenever the attached event is triggered.
We can refer to this code as โSide-effects codeโ, and it's typically not part of the normal top-level code of our component. Instead, we want this code to execute only when specific events occur, usually when a user interacts with our UI. To achieve this, we encapsulate this code within a handler function."
The purpose of sideEffects in react:
Thus far, we've explored the concept of top-level rendering code and event-handler-based side-effects code in React components. However, React's capabilities extend beyond these fundamentals. React can do even more. It can fetch data, talk to other websites or services, and do extra things beyond its regular job.
So where do you think we should put this data? It's apparent that the code used for data fetching isn't directly involved in rendering content on our screens, reason why we canโt have this code on top level, also the rendering code should be free from any side effects code like fetching data, Itโs a side effect code but we canโt have it inside event handler, remember they are only executed when user events are triggered.
so we need to think of a way to place this side effects code inside our component, but not on top level nor inside event handlers.
We want to fetch data as soon as the webpage loads, right after the components are rendered. There's no specific event to trigger a handler upon rendering. That's where โuseEffectโ comes into the picture.
Code placed inside โuseEffectโ is executed after the component is rendered and committed, meaning it runs after the DOM is updated. This ensures that it doesn't interfere with the top-level code or cause side effects during rendering. That's why it's a perfect choice for executing this type of code.
Now that we understand the importance of โuseEffectโ, let's dig deeper into how we can use it to establish connections with 3rd-party APIs or external systems.
Effect code is executed after the component is rendered and committed, which means it runs after the DOM has been updated.
UseEffect:
We import โuseEffectโ and call it at the top level of our component, similar to how we use โuseStateโ. โuseEffectโ should not be placed inside any nested functions or hooks unless it's within a custom hook.
If we observe above code, we have called useEffect on top level inside the App component, itโs like calling a function and passing arguments, here the only argument we passed is the function(arrow function) inside which goes our side effects code.
Letโs see useEffect in action:
Here's the link to the above code. Please try it yourself.
If we observe the developer tool in our browser console, we find two consecutive logs. The first one is the code at the top level, and once the component is rendered and the DOM is updated, the code inside the โuseEffectโ is executed.
This indicates that the code inside โuseEffectโ runs only after the component is rendered.
Effect Dependencies:
The first argument we pass to the โuseEffectโ function is the arrow funtion, and โuseEffectโ also takes an array of dependencies as the second argument.
Running code after every render sometimes makes the code slow and sometimes it's incorrect. We don't want our code to establish a connection with an external API on every render; that's unnecessary and makes our code slow.
Also, if we are fetching data from an external API, we don't want to fetch data each time the component re-renders, to prevent his we add dependecy array to useEffect hook:
1. No array: If the array is omitted, the effect runs after every component re-render.
2. Empty array: The effect runs after the component renders for the first time and never again.
3. Array with values: The effect runs after the component renders and runs again only when one of the values in the array changes. React compares the previous array values with the current render array values, and if no changes are found, it skips rendering the effect's code.
These array values should be values that affect the code inside the โuseEffectโ. We can't choose these values randomly. If React determines that these values might change and they affect the decision-making process of how the component renders, we might want to include these values in the dependency array.
Clean up function:
Within the โuseEffectโ function in React, we have the option to return a cleanup function. The cleanup function is executed before each time the effect function runs, except for the first time, and one final time before component unmounts.
But why do we need a clean up function in the first place?
Itโs purpose is to clean up the side effects code.
You might have noticed that the code is logged to the console twice; this is because useEffect runs twice in react development stage, Itโs Reactโs way of helping us catch bugs. React remounts the component after it mounts for the first time.
To understand better, let's consider an example:
When the home page loads, we need to establish a connection to external resources immediately. This connection should be made when the component mounts and should persist as long as the user remains on the home page
However, if the user navigates away from the home page to a different component and then returns, we don't want to re-establish the connection again. This issue can sometimes go unnoticed, which is why, during development in React's 'strict' mode, it may appear as if the code runs twice within a component. React intentionally remounts every component once after itโs initial mount, allowing us to catch these types of bugs early.
Here's where the cleanup function plays a crucial role - it helps us address and rectify such bugs.
The cleanup function ensures that the connection is automatically disconnected when the user closes the application or navigates to a different page. It's invoked just before the โuseEffectโ code runs, except for the first time, and when the component unmounts."
It's worth noting that React's behavior of remounting once after the initial mount only occurs during development. In a production environment, this would log only once. You can confirm this by turning off the 'strict' mode of the development behavior, but itโs not recommended.
What we have learned:
How the โuseEffectโ hook is a powerful tool for handling side effects in React. Remember to wrap your side effect code in โuseEffectโ to prevent issues.
Learned that the code inside โuseEffectโ runs (after component rendering and DOM updates) is vital for managing side effects effectively.
The second argument of โuseEffectโ allows us to control the behavior of the hook.
We can omit it (code runs after every component mount)
Use an empty array (code runs after initial component mount and never again), or
Add dependencies values to the array to manage how the code executes (code runs after initial component mount and every time dependency value changes).
Cleanup functions within 'useEffect' play a critical role in preventing issues related to side effects. They help us catch bugs.
I hope you found this exploration of useEffect hook and side effects in React informative and valuable for your projects.
If you have any questions or feedback, feel free to leave a comment below. Happy coding!"