This course has been updated! We now recommend you take the React Performance course.

Check out a free preview of the full State Management in Pure React, v2 course:
The "Refactoring & Custom Hook" Lesson is part of the full, State Management in Pure React, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Steve demonstrates how to combine two hooks into one, and builds a custom hook called useLocalStorage to store local state. Local storage can be used by any component within the app, instead of using the useState.

Get Unlimited Access Now

Transcript from the "Refactoring & Custom Hook" Lesson

>> I've got that in place. I can pull this out into useLocalStorage, right? There's a hook that I'm making up out of nowhere, what should useLocalStorage do? Well, it should do what the useState does to manage the state. And when that state changes, it's just stored in localStorage, right?

[00:00:18] So it's basically taking these two pieces, this right here and this part up here, and we're just rolling it into one. So now, if you need to do this other places in your application, you now use this obstruction that you've created for yourself. So let's try it out.

[00:00:34] We'll make a function called useLocalStorage. And we know that useState takes a default value, rright? So I could say, initialValue, which is what I believe it's called in useState under the hood. Let's see, initialState. But that's problematic, because we know that we're using a key in here for where we want to store it in localStorage, and we do not want every.

[00:01:03] If we're gonna make a reusable hook, them all overriding each other probably not great. Right, this is a personal opinion. So we'll take an initial state. I'm actually gonna make the key the first. I'll make it the second, just keep it as a similar API. So we'll say, key, in this case, and this will be where do we wanna store it in localStorage.

[00:01:26] All right, so now what we can do is we pull this in there as well. We'll give ourselves, this is so I could have it in its own file. Could I keep it in, say? That would totally work, we can leave that there too. So we'll say, getItem with the key.

[00:02:01] We will go and get that key again here. All right, so go ahead and pull it out in both times. Actually, let's put that back in a function. That will return initialState, right? So go ahead, look for it in localStorage. If you get, it return that, otherwise whatever they said the initial value was works for us.

[00:02:36] Cool. And then what we'll do is, we'll say. Now, I'm just gonna name these value and setValue because I don't know what they are before we knew it was account. Now we don't necessarily know its account, and this is why useState puts it in an array. With an object, you can do structure but it has to be the name of the keys, right?

[00:02:58] The reason it gives us, JavaScript functions can return two values, right? So they can return an array where we can name the first thing in the array value and setValue. Counter and setCount, user and setUser, grudge and setGrudge, right, so on and so forth, right? It gives us a flexibility in naming here.

[00:03:16] So we can go ahead and we can try that out. So we'll say the initial value here is useState. I'll just use that get shorthand that we had before. All right, so we'll get that, and then we'll also just register the effect of the same time, useEffect And that useEffect is going to be that localStorage setItem at the key.

[00:03:47] And then we will, I just need to change one thing, as I was talking and coding. Cuz we're gonna take whatever the name of the value is, we'll use that. So this is in case it's called counter, whatever, they'll get stored in there. Cool, and so now we have the ability to get something at localStorage.

[00:04:14] We have that storage and localStorage put in place here. We're setting some state. The last thing we need to do is kind of just match an API that matches useState. Cuz there's basically setting the state, and it's also registering that whole ability to read and write from localStorage is simply an abstraction over the two things that we had before.

[00:04:30] We return value and set value. So, as far as the user knows, it's got the exact same API as react.useState. Under the hood, it is using react.useState, but it's also taking care of all this localStorage reading and writing. It's effectively the code we had before, just a little more dynamic before we had hard coded in some strings.

[00:04:50] And we knew that was a count. We knew that we were putting a count state, because it's a little bit more reusable. We had to put in some variables that made it a little bit more squirrely. But, generally speaking, it is simply we useState and useEffect with this localStorage logic all kind of rolled into one.

[00:05:05] All right, with the decent amount of coding and talking, let's see how that went for us. So now I can say, useLocalStorage, and the initial state is going to be, let's say 0. I'm gonna give it a new key in this case, just so we can separate it from other localStorage that we had before.

[00:05:25] We'll call it just count in this case. All right, so it is 0. It is 5. It's assigned not used, let's see what we've got in here.
>> Are you trying to use value here for values even set? That was tripping me up a little bit there.
>> Let me actually see what, cuz I was talking and typing and refactoring.

[00:05:57] I wanna see what the localStorage, and I will tell you what I intended on doing [LAUGH]. We've got account in there, it's getting stored as an empty object, cool. So then we set, we'll set the key, we've got account. Probably if I'm gonna care about the value, I should listen to that, right?

[00:06:31] Let's see how that goes from here. That's fun. All right, so for the user, right, I got of not difficult in my own dependencies, right? So on the initial one is immediately, cuz this is a function we're getting and it was getting set to a non value. So this is all, a lot of times what do we have to do is squirrely stuff in code.

[00:07:14] Do I love the localStorage API? I do not, I don't, and the squirrely parts of this are dealing with localStorage. And in a more robust situation, we would try and catch, cuz json.parse loves to throw errors like it's nobody's business, right? That becomes complicated code. If we needed to do that more than once in managing the state in our application, I don't wanna write that more than once.

[00:07:34] It's cuz every time you write it, it's a chance that someone's gonna make mistake, right? I made a mistake. The idea here is we have it bundled up in an abstraction of useLocalStorage as far as anyone else using this now, right? Once we've got it down, they use uselocalStorage, and it's the same API as useState, other than having a key, right?

[00:07:53] They're not thinking about the other parts. And it just is automatically gonna store stuff in state for us, right? And now we've bundled that up by kind of combining two hooks into our own abstraction, right? And that's kind of one of the powers. Cuz now we can put this in an own file, call it useLocalStorage.js.

[00:08:11] Any other component can import it instead of using useState. You're going to get useLocalStorage is gonna be useState with the ability to store it based on that key automatically. And sart to build up your own toolbox of different abilities and be able to iterate it from there. So useState does work a little bit differently than the component ones as well, right?

[00:08:34] I'm sorry, useEffect works a little bit differently than the component ones as well. And it's also little subtle things. And really, the big difference is not necessarily that the API is implemented differently. There are just slightly different implications based on how JavaScript works, right? And what I'll point out here is that in a class-based component, right?

[00:08:57] Class at the end of the day spits out an object that has methods and stuff like that, our state is stored in an object. In JavaScript, we pass objects by reference, right, and we passed primitives by value. Even if we were to pass an object to setCounter or something like that, we are wholesale replacing the object with a new one.

[00:09:16] So this works a little bit differently than maybe componentDidMount or componentDidUpdateMine. So, I'm gonan commit this real quick And I'm just going to make a new ranch, We'll call example-use-local-storage, Cool. I am using that so I can switch, there is one that you should have called component-state-completed which is kind of before we refactored the hooks.

[00:10:00] And this is just so I can show you something very quickly here.