React Custom Hooks (Advanced)
Explore how to create advanced custom hooks in React that combine useState and useEffect to manage state and sync it with local storage. Understand naming conventions, reusability, and how to handle keys to avoid data overwrites. This lesson helps you abstract complex logic into reusable hooks to keep components lean and maintainable.
We'll cover the following...
Thus far we’ve covered the two most popular hooks in React: useState and useEffect. useState is used to make your application interactive; useEffect is used to opt into the lifecycle of your components.
We’ll eventually cover more hooks that come with React – though we won’t cover all of them here. Next, we’ll tackle React custom Hooks; that is, building a hook yourself.
We will use the two hooks we already possess to create a new custom hook called useSemiPersistentState, named as such because it manages state yet synchronizes with the local storage. It’s not fully persistent because clearing the local storage of the browser deletes relevant data for this application. Start by extracting all relevant implementation details from the App component into this new custom hook:
So far, it’s just a function around our previously used in the App component used useState and useEffect hooks. Before we can use it, let’s return the values that are needed in our App component from this custom hook:
We are following two conventions of React’s built-in hooks here. First, the naming convention which puts the “use” prefix in front of every hook name; second, the returned values are returned as an array.
While this example returns a state and a setter, a more complex react custom hook with multiple functions could return a whole suite of utilities. For instance, you could return a function to clear the storage, a function to validate the input, and the state itself. This allows you to keep the component lean while the hook handles the heavy lifting.
Now we can use the custom hook with its returned values in the App component with the usual array destructuring:
Another goal of a custom hook should be reusability. All of this custom hook’s internals are about the search domain, but the hook should be for a value that’s set in state and synchronized in local storage. Let’s adjust the naming therefore:
We handle an abstracted “value” within the custom hook. Using it in the App component, we can name the returned current state and state updater function anything domain-related (e.g. searchTerm and setSearchTerm) with array destructuring.
There is still one problem with this custom hook. Using the custom hook more than once in a React application leads to an overwrite of the “value”-allocated item in the local storage. To fix this, pass in a key:
Since the key comes from outside, the custom hook assumes that it could change, so it needs to be included in the dependency array of the useEffect hook. Without it, the side-effect may run with an outdated key (also called stale) if the key changed between renders.
Another improvement is to give the custom hook the initial state we had from the outside:
Here is the complete demonstration of the above concepts: