useEffect
is a react hook that lets you sync react code/ application with an external system that does not use react such as an API
If you are looking for a React Native Chat SDK to build in app chat messaging application, you can consider DeadSimpleChat React Native SDK
How to use useEffect?
You need to call useEffect
at the top of the component where you are using it because it is a React Hook (Hooks are just JS functions)
Basic Syntax
useEffect(() => {
// the logic of the side effects
}, [dependencies-array]);
A Simple Example:
Parameters
the setup function: The setup function contains the logic for the side effects. This setup function can also optionally return another function that is the clean up function
When the component is added to the DOM. First the React will run the setup function then after every re-render when the dependencies have changed the react will run the clean-up function and then the setup function
Dependencies Array Optional : The list of values
Dependency array is the second argument in the useEffect hook. It contains all the reactive values that are refrenced in the setup code
Reactive values are:
- Props: Values that are passed down from the parent component
- State: local storage for the component
- Other Values: Various functions or variables that are declared within the component body
The effect will run every time the reactive values that are in the dependency array changes. React does a shallow check with Object.is and if there is a change react re-runs the effects
Empty Array : Means that there are no dependencies and the effect will only run once when the compnent is rendered for the first time
No Array : If you do not include the array then the effect will run at every re-render of the component
Returns
The useEffect returns null
Caveats
Placement of the useEffect
- Only at the Top Level : You need to invoke the
useEffect
hook only at the top level because it is a react hook - Conditional logic: You can't call useEffect inside loops of conditionals. If you need to do this extract a new component and move the state into it
Purpose of useEffect
- Only for syncing with an external system: If you not trying to sync with an external system then you probably do not need the useEffect Hook. External system means an API or any other code that is not react
- If you are not dealing with side effects, you probably do not need to use useEffect
Strict Mode Consideration
- Inside the Development mode : When you are running the useEffect in development mode the
setup
andcleanup
functions will run an extra time before the first real run. This ensures that the code is reliable, that is the clean up is properly cleaning up the setup code
Dependency Caveats
Having functions and Objects as Dependencies
If you have Objects and functions that are defined in the component as dependencies in the useEffect hook. It could lead to unnecessary re-runs as Object or function notation creates new Objects and functions this could lead to useEffect running at every re-run
Solution
- Remove ununessory functions or Objects.
- Use other hooks like useCallback or useMemo to optimize the dependencies
- Remove non-reactive logic out of the component or the useEffect Hook it the logic does not need to be there
Server Side Rendering
UseEffects can only run on the client side. Do not try running it on the server side.
Usage
How to connect to an external system using useEffect
In this example we are going to learn how to connect to an external system using the useEffect
Let us consider a component that needs to be connected to an external system.
For Example an network, like a browser API or a socket connection or a third party library
These systems are not controlled by react and hence are called as external
Step 1: Setting up
When the component is rendered for the first time, the function that we provided to the useEffect
is executed
Here we will establish a connection to the external system
Step 2: Cleaning Up
- It is necessary to disconnect to external systems, when they are no longer needed. This is essential to prevent memeory leaks or unwanted side effects
- The clean up is done by returning a function from
useEffect
caallback. The callback runs - 1. Before the component is removed from the UI and
- 2. Before the useEffect reruns because of dependency changes.
step 3: Dependency Array
- Dependency array contains reactive values (props, state, functions, variables inside components that should trigger a re-run of useEffect)
- In the above example whenever the
serverUrl
or thechatRoomId
changes theuseEffect
re runs
step 4: Lifecycle illustration
- On Mount: establish the connection
- On re-render : Whenever dependencies change re-render the use-effect and disconnect and reconnect with new values
- On unMount : Disconnect from the external system
step 4: development mode
- In development mode the react runs the cleanup function one extra time before running the useEffect code. This is to test whether the cleanup function is working properly or not
- If this causes some problem in your application. This means that the clean up code is not working properly and not cleaning up after the Effect has taken place. You should fix the clean up code
step 5 : Best Practices
- Independent Operation: You should write every react effect as an independent from other effects. This ensures that no effect relies on other effects and the code is straightforward
- Setup/Cleanup Cycle Always write the clean up code keeping the setup code in mind, so as to properly unwind the setup after the effect has taken place.
Some Examples from basic to advanced
Example 1: News Feed
In this example we have a news feed component, that connects to an external system that is defined in the news.js
file
The user clicks on the "Read News" button and the News Feed component is rendered on the page.
We are running the code in the development mode so there will be an additional connect/disconnect cycle.
You can try and adjust the feedTopic
and the serverUrl
to observe the Effect connecting and disconnecting from the news feed
"Close News" will disconnect the Effect for the last time
App.js :
News.js:
The newsFeed component subscribes to the news topics from 3 given choices. here is what is happening in the above example
- App Component The App component decides whether the news feed is visible or not and shows a selection of new topics available to the visitor
- useEffect : In the
NewsFeed
theuseEffect
hook manages the connection to the server. Whenever thefeedTopic
or theserverUrl
changes theuseEffect
unsubcribes from the old topic and subscribes to the new topic - Create Subscription In the file
news.js
the utility function connects to the news services. This is just a demo, in the real app here would be the logic of connecting and disconnecting from the news feed.
Example 2: Tracking Screen Resizing
In this example we are going to track browser window resizing. This is a common use-case where use-effect can come in use.
Here we are going to listen to the resize
event, using which you can keep track of the browser window's height and width.
Here we are showing how react can be used to listen to global browser events using the useEffect hook and then you can subsiquently take some action based on the dimensions of the browser window
Here is how this code is working
- Init: We are initializing the component's state with browser's windows current dimensions using the built in
window.innerHeight
andwindow.innerWidth
functions - useEffect The useEffect hook calls the handleResize function whenver the resize event triggers
- Cleanup : Inside the
useEffect
we have a clean up function that cleans up the event listener. This is done so as to avoid issues like memory leaks - handleResize The function updates the state whenever the window dimension changes
- Render function The render function renders the UI on the screen
Using useEffect in Custom Hooks
Effects are basically an escape hatch from the react ecosystem. They are basically a way to handle side-effects in functional components
If you have to write repeatable logic in different components when dealing with certain side-effects or external integrations like calling an API again and again in different components
This article is brought to you by DeadSimpleChat, Chat API and SDK for your website and apps
It is better to encapsulate the Effects code inside a Custom react Hook
It helps with code reuseability and makes the code more consise and readable
Custom Hooks allows you to abstract the Effects logic away from the component and focus on whatever the compnent needs to do.
Example 1: Fetching user data from an API
In this example we want to fetch user data from an API. Here many components want to fetch the data.
Instead of using useEffects in each of these components we are going to create an custom hook that would encapsulate the fetching logic and we will use that custom hook whenever we want to fetch the user data.
Creating the Custom Hook: useUserDetails
the useUserDetails
hook accepts a uniqueUserId
and uses the useEffect
to fetch the details about the user and returns the userData
Any component can use the useUserDetails hook to obtain details about the user without knowing how the details are being obtained
using the custom Hook : useUserDetails
Example 1: Creating a useLocalStorage Hook
In this example we have an app where we store users preferences in localstorage and access the preferences in various components.
Instead of writing the logic of reading and writing to localStorage we are going to extract away the logic in a custom localStorage Hook
Note: If you are interested in reading more about this read our guide JavaScript LocalStorage
App.js :
import "./styles.css";
import { useLocalStorage } from "./useLocalStorage.js";
function UserSettings() {
const [username, setUsername] = useLocalStorage("username", "");
return (
<>
<label>
Name:{" "}
<input value={username} onChange={(e) => setUsername(e.target.value)} />
</label>
<h1>Hello, {username}!</h1>
</>
);
}
export default function App() {
return (
<>
<h2>Settings:</h2>
<UserSettings />
</>
);
}
useLocalStorage.js
import { useState, useEffect } from "react";
export function useLocalStorage(key, initialValue) {
// try to get the value from localStorage if unable use default value
const localStorageValue = localStorage.getItem(key);
const valueToUse = localStorageValue ? JSON.parse(localStorageValue) : initialValue;
const [value, setValue] = useState(valueToUse);
useEffect(() => {
// save to localstorage the value changes
localStorage.setItem(key, JSON.stringify(value));
}, [value, key]);
return [value, setValue];
}
- We are sync
localStorage
with state using theuseLocalStorage
hook - The
useLocalStorage
hook tries to get the value from the localStorage and when it is unable to find the value it uses the default value - we are using the useState hook inside the useLocalStorage to save the value in localStorage whenever the value changes
- The usLocalStorage returns a setter function to both display the value and update the stored value at the same time
Controlling a widget that is not built with react
Many times you need to connect with code that is not built with react. Maybe it is built with some other library like JQuery etc or something else
We will study an example where we control a widget which is not built with react using the useEffect
hook
Example: Controlling an Audio widget with react useEffect
Let us consider a Audio widget, which is not built with react and we need to integrate it with the react code
App.js
Specifying Reactive dependencies
In useEffect you cannot choose your dependencies. Every reactive value must be stated as a dependency
The useEffect dependency list is determined by the surrounding code
let us look at an example to understand this better
All reactive values must be specified as dependencies, here uniqueUserId
and the apiEndpoint are reactive values and hense must be specified as dependencies.
Props and variables and functions declared inside of your component are reactive values
The reactive value changes will cause the component to re render.
function HelloUser({ userName }) { // `userName is a prop and hence a reactive value
const [prefix, setPrefix] = useState('Hello User'); // the prefix is state and hense a reactive value
useEffect(() => {
document.title = `${prefix}, ${userName}!`;
}, [userName, prefix]); // useEffect needs to have both the dependencies mentioned in the dependency array
// ...
}
userName is a prop hence it is a dependency
prefix is a state and hence it is also a dependency
So, both of these are mentioned in the dependency array
Thus explaining that all the reactive values must be mentioned in the dependency array
You might be interested in some of our other articles
- useLayoutEffect vs useEffect with examples
- React useDeferredValue
- React useMemo Vs useCallback
- React Server Components with Next.JS: The Complete Guide
Conclusion
In this article we have learned about React useEffect using use-cases and examples
I hope you liked the article and thanks for reading