Using Custom Hook Functions in ReactJS
Why would we use custom hooks? There are 2 reasons to use them:
- An easy way to have access to the React state
- A safe, namespaced place to use side-effects
Say you have React component that is a button, and when you click the button, it increases a number. So the first time you click, the button shows 1, then 2, and so on. It’s basically a really simple app because it doesn’t do anything other than increase a number and render a button, so we basically write it like this:
When we’re thinking about what a custom hook is, it can be helpful to think of them as regular old hooks. So what do regular old hooks return? To answer that, we can look at the React.useState() we used. We used it like this:
const [count, setCount] = React.useState(0);
So, we still only get back a single variable, it just happens to be an array. It returns an array with two variables, count and setCount.
So if it would be helpful, you can imagine a custom hook would look like this:
function myCustomHook(initialState) {
const [state, setState] = React.useState(initialState); ... return [state, setState]
}
While that function doesn’t start with “use” like “useState” does, and so React would throw warnings, it is still a hook function. A hook is just a piece of code, a function, that uses useState and useEffect inside of it and returns some piece of state. So now we can convert this line
const [count, setCount] = React.useState(0);
… into something like:
const [count, setCount] = useCount(0)
So now, we’ve replaced React.useState() with a custom hook that we’ve created ourselves. Why would we want to do this? It might be because perhaps we want to store the state (ie the number) in a way that we can persist it after the user refreshes their browser. So we can have the number say 1, 2, 3, then the user refreshes the page, and we should still have the number start at 3. So to do this, we’ll use localStorage because the localStorage API is simple.
So now if you take a look at what I’ve done, you’ll notice that our state persists in the local storage. You can reload and see your changes will be persisted until of course you can manually decide to delete it from local storage from your browser. And while the code itself isn’t important, you should take away two things:
- You can pass in a function to useState which will determine what will be the default state when the component first loads. So, this is exactly hat we need in this case, because when the component loads, we’re going to first check to see if there’s a value for ‘count’ in local storage, and provide the app with the value and say “use this for my initial state”, or use the default of 0 if it doesn’t exist (you have deleted it or something). This is done by using this line
window.localStorage.getItem("count") || 0
2. We’re using a useEffect with default parameters (it’s going to run every time the button is pressed — which is exactly what we want for now.
Ok that’s fine, but we haven’t done anything related to custom hooks. We haven’t created a custom hook yet. But the reason we haven’t, is because the real reason, the important reason or the “why” behind the “why should I use custom hooks” is that they are really nothing special. Again, they are just functions that use useState or useEffect, so they somehow hook into the state or perform a side effect, but are otherwise just convenience functions. I mean, we can be done right now with this application and call it a day, and if I wasn’t about to demo custom hooks, I probably would. But now, let’s write actually write a custom hook and see how things change.
And that’s it. Even though we’re doing the same thing, we’ve hoisted, or move up, the code that interacts with the state, and then return the value that we need. It’s so simple that we can actually just swap the words useState to useLcoalStorage, and it will still work.
However, in practice, useState is a slightly more involved hook because it is customizable. Ie, it should not be time to expand our code to do the things like making it support not just the string ‘count’ but any variable at all. We should also look into serializing and deserizling, and you should do all that and more, but it is out of the scope of this article right here. So for now, goodbye, and until next time, follow along as I go through the EpicReact course taught by Kent C. Dodds.