Taking Control of Component Updates in ReactJS with useUpdateEffect
ReactJS, the incredibly popular JavaScript library, has been a game-changer for web development. It enables developers to create intricate, highly dynamic, and interactive UIs with relative ease. The impressive capabilities it offers explain why many businesses seek to hire ReactJS developers for their projects. Among its many features, hooks, introduced in React 16.8, have revolutionized the way we, and the ReactJS developers we hire, manage state and side effects in functional components.
However, while useEffect is great, it’s a common scenario that we only want to perform an action when certain values have changed, not on the initial render. The built-in useEffect hook runs both after the first render and after updates, which can sometimes lead to undesired behavior. To circumvent this, we need something that mimics the componentDidMount and componentDidUpdate lifecycle methods from class-based components. This is where useUpdateEffect comes in, and underscores the value when you hire ReactJS developers who understand these nuanced aspects of the library.
What is useUpdateEffect?
`useUpdateEffect` is a custom hook that you can utilize to run side-effects only when a component updates, not when it initially renders. Essentially, this hook skips the effect on the initial render and only runs on subsequent renders (i.e., when the component updates).
Here’s a basic implementation of useUpdateEffect:
```javascript import { useEffect, useRef } from "react"; function useUpdateEffect(callback, dependencies) { const firstRenderRef = useRef(true); useEffect(() => { if (firstRenderRef.current) { firstRenderRef.current = false; } else { return callback(); } }, dependencies); } ```
This custom hook leverages useRef to keep track of whether the component is rendering for the first time. On the first render, it simply sets the `firstRenderRef` to `false` and skips calling the callback. On subsequent renders, the `callback` function is called, executing the side-effect.
Now that we’ve got the basics covered, let’s dive into a couple of practical examples of using `useUpdateEffect`.
Fetching Data on Component Update
In this example, we have a component that fetches and displays user data based on a userId prop. We want to re fetch the data whenever the userId changes, but we don’t want to fetch data when the component is first rendered. Here’s how we can achieve that using `useUpdateEffect`.
```javascript import React from 'react'; import useUpdateEffect from './useUpdateEffect'; function UserProfile({ userId }) { const [user, setUser] = React.useState(null); const fetchData = async () => { const response = await fetch(`https://api.example.com/users/${userId}`); const data = await response.json(); setUser(data); }; useUpdateEffect(() => { fetchData(); }, [userId]); return ( <div> {user && ( <> <h1>{user.name}</h1> <p>{user.email}</p> </> )} </div> ); } export default UserProfile; ```
Here, we’re calling `fetchData` inside `useUpdateEffect`, which will be triggered only when `userId` changes, not on the initial render.
Updating Document Title on Component Update
Consider a scenario where you have a component that displays a counter. You want to update the document title with the current count whenever the counter is updated, but not when the component is first rendered.
```javascript import React from 'react'; import useUpdateEffect from './useUpdateEffect'; function Counter() { const [count, setCount] = React.useState(0); useUpdateEffect(() => { document.title = `Count: ${count}`; }, [count]); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } export default Counter; ```
In this example, we’re using `useUpdateEffect` to update the document title every time `count` changes, but not on the initial render.
Implementing a Light/Dark Mode Switch
In this example, let’s imagine we have a light/dark mode switch in our application. Whenever the mode changes, we want to store the current mode in localStorage so that we can maintain the user’s preference across sessions. However, we don’t want this to run on the initial render.
```javascript import React from 'react'; import useUpdateEffect from './useUpdateEffect'; function ThemeSwitch() { const [theme, setTheme] = React.useState(localStorage.getItem('theme') || 'light'); useUpdateEffect(() => { localStorage.setItem('theme', theme); document.body.className = theme; }, [theme]); return ( <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}> Switch to {theme === 'light' ? 'Dark' : 'Light'} Mode </button> ); } export default ThemeSwitch; ```
Here, `useUpdateEffect` is used to update the localStorage and the body className only when the `theme` state changes, not on the initial render.
Conclusion
React Hooks have significantly simplified the process of managing state and side-effects in functional components. These capabilities are part of what makes ReactJS a powerful and flexible library, and why you might want to hire ReactJS developers for your project.
However, as we’ve seen, there are times when you might want to run side effects only when certain props or state have changed, not on the initial render. The `useUpdateEffect` custom hook can be a valuable tool in these cases. Expert ReactJS developers are adept at leveraging such tools to deliver highly efficient applications.
As with any powerful tool, however, it’s crucial to use it wisely. Whether you’re a seasoned ReactJS developer or are looking to hire ReactJS developers, ensure you understand the implications of skipping effects on the initial render, and always be conscious of how your component interacts with the rest of your application.
Table of Contents