UseEffect dependency array and object comparison!
Tags: react, javascript, webdev, tutorial
Published: 2021-03-30 14:48:29

Hello folks!


If you are performing any side effects in your function, the **Effect** hook have to be there.  This useEffect hook takes first  parameter  as a function  to perform side effect and second parameter, *a dependencies array*. If you do not wish to perform side effects on every render (which is the case almost every time), you need to pass something to this dependency array or at least an empty array. This array will re-run useEffect, if the values inside it changes. This will work perfectly fine when the values passed in the dependency array are of type boolean, string or numbers. But it will have some gotchas when you are dealing with complex values such as objects or arrays. 

Before diving into the solution of the problem, let’s first understand this problem in detail.

React always compares objects and arrays with their reference. This may affect the execution of useEffect in any of these two cases - 
1- Object or array is exactly the same, but they are compared using different references.
2- Object or array have different values, but they are compared using the same reference.
In both the cases, useEffect hook will not perform correctly leading to the bugs in our application. 

There are possibly two solutions to this. Let’s understand them in detail - 

### Create dependency on details 

Consider an object with all the user details passed as a prop to the function. In your app, you want to perform the side effect only when the username of a user changes. So, in this case, the dependency becomes quite clear! Instead of passing whole user details objects to the useEffect, pass only the detail which matters. Something like this - 

```javascript

function UserProfile({userDetails}) {
	const [error, setError] =  useState(‘’);
	
	useEffect(() => {
		if(userDetails.username) {
			// Do something…!
}
}, [userDetails.username])
}

```

This way, useEffect will compare the exact value and will re-run only when the username changes. This approach is suitable for small no of dependencies, but will not be clean and scalable if the array grows. 


### Memoizing the object

One more solution for this problem could be creating a new object every time. That way, we can always be sure that all changes are recorded and comparison is not happening on reference of that object. To better understand, let’s see the code -
```javascript
function UserProfile({ userDetails }) {
	const [error, setError] = useState('');
	const [user, setUser] = useState({
		username: userDetails.username,
		email: userDetails.email,
		address: userDetails.address,
	});

	useEffect(() => {
		if (userDetails.username) {
			// Do something…!
		}
	}, [userDetails.username]);
}
```

As you see in code, we created another copy object of the same object. Though this seems to solve the issue, there is a problem with this approach too. We all know creating objects in javascript is an expensive  operation and we are trying to do that twice!! Apart from that, we are also duplicating the code which is again not a good practice to follow. 

To solve all these problems, memoizing the object becomes a very simple and easy to maintain solution. Let’s see how - 

Memoizing an object means we try to maintain a memory of the object. In better terms, we **cache** an object and maintain its one copy in our function. When the function re-renders, this same copy will be used in our function until any property of that object does not change. This way, we minimize the expensive operation of creating objects and also maintain an approach to catch the change. 

For this memoizing, we use **useMemo hook** react. Let’s see the code - 

```javascript
function UserProfile({ userDetails }) {
	const [error, setError] = useState('');
	const { username, email, address } = userDetails;

	const user = useMemo(() => createUser({ username, email, address }), [
		username,
		email,
		address,
	]);

	useEffect(() => {
		if (username) {
			// Do something…!
		}
	}, [user]);
}
```

As in the above function, the createUser function will get called only when the username, email and address changes and new **User** object will be created.This way we make sure to compare correct copy of object in the dependency array and also optimize the unnecessary re-renders, 

This is one of the tricky topics while working with useEffect as we tend to miss the fact that react will compare the reference of the object. Passing objects directly to useEffect will make the function buggy and we end up spending a lot of time figuring out what exactly is wrong!! (happened with me a lot!)

That’s it for this article and I hope it has helped you in some way! Please let me know how you solved the problem while passing objects to the dependency array? And of course, thoughts/comments/feedback on the article :)

You can also connect with me on [Twitter](https://twitter.com/hey_yogini) or [buy me a coffee](https://www.buymeacoffee.com/heyyogini) if you like my articles. 

Keep learning 🙌