Best Practices for Managing Side Effects in React with `useEffect`

When working with useEffect in React, the way you handle subscriptions is crucial for maintaining performance and avoiding memory leaks. Let’s explore two forms of useEffect for managing authentication state changes using Firebase’s onAuthStateChanged and understand why one approach is superior.

Handling Subscriptions with Cleanup

First, consider the following example where we properly manage the subscription by including an unsubscribe mechanism:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
useEffect(() => {
const auth = getAuth();
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
const userProfile: UserInfo = user.providerData[0];
setUserInfo({
providerId: userProfile.providerId,
uid: userProfile.uid,
displayName: userProfile.displayName,
email: userProfile.email,
photoURL: userProfile.photoURL,
});
}
setLoading(false);
});

return () => unsubscribe();
}, []);

Handling Subscriptions Without Cleanup

Now, compare it with a version that does not manage the subscription cleanup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
useEffect(() => {
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
const userProfile: UserInfo = user.providerData[0];
setUserInfo({
providerId: userProfile.providerId,
uid: userProfile.uid,
displayName: userProfile.displayName,
email: userProfile.email,
photoURL: userProfile.photoURL,
});
}
setLoading(false);
});
}, []);

Why the Unsubscribe Form is Preferable

Using the form with unsubscribe is generally better for several reasons:

  1. Memory Management:

    • Subscriptions persist until explicitly cancelled. By calling unsubscribe in the cleanup phase of useEffect, you ensure the subscription is terminated when the component unmounts or the effect dependencies change, preventing memory leaks.
  2. Avoiding Multiple Subscriptions:

    • If the dependencies of the useEffect change, the effect re-runs. Without cleanup, each re-run creates a new subscription, leading to multiple active subscriptions and potential issues. The unsubscribe method ensures only one active subscription at a time.
  3. Best Practices:

    • Explicitly handling side effect cleanups is a best practice in React. It ensures your component releases resources correctly, leading to predictable behavior and preventing issues caused by stale listeners or handlers.

Conclusion

While the second form (without unsubscribe) may be adequate for simple scenarios or quick experiments, the first form (with unsubscribe) is more robust. It aligns with React’s best practices for managing side effects and resource cleanup, ensuring your component remains performant and reliable, particularly in larger or more complex applications. Always favor the approach that includes cleanup to maintain optimal performance and avoid potential pitfalls.