State Management in Pure React, v2 Refactoring & Hooks
This course has been updated! We now recommend you take the React Performance course.
Transcript from the "Refactoring & Hooks" Lesson
>> Let's talk a little bit about React Hooks. So React Hooks gives us a different way to think about management of state. So this .state is a property on the class, and this .substate is a method. We never define those ourselves, but when we said, class counter extends component, React.component in this case.
[00:00:20] We are inheriting those methods. And that allow us to update the value and trigger the render, so on and so forth. Few years ago, React implemented another way to create components which is just to have a function. And that function took in props and it did stuff. And whatever came out the other side was rendered to the page.
[00:00:42] Now, you'll notice that I didn't say the word state in that explanation. Cuz there was no concept of state. It was basically you have some components that do need to manage the state but a parent component state is the children components' props. So maybe a list of users has some state as you add users or remove users, but each individual user just gets that state from the higher component.
[00:01:02] So it was useful in the cases where you didn't need to manage any state. It was nice and clean because you didn't have to do all this binding. And you didn't have to extend from component. And you didn't need a constructor, yada, yada, yada, yada. And when they first came out, I used them all the time because they were cool.
[00:01:22] And then as I got older and saltier, I use them almost never because what would happen is eventually that component would need some kind of state. And you'd have to change it into a class based component. And so I got very ordinary and just started to make very simple class based components that only had a render method so that when I needed state, I didn't have to rewrite it.
[00:01:41] And sure, you could say, couldn't you write a JS code shift or code mod to do it and isn't there a VS Code plugin I'm sure there is. But it was still tricky enough that I just decided it wasn't worth it. Hooks came out and gave us a way to manipulate state in functional components.
[00:02:00] And functional components are cleaner and easier as we begin to refactor our counter, we'll actually see that it becomes a much simpler component as we go through. And then we'll kind of look at some of the things that we saw with this as a state, like how does that actually translate into the kind of hook land?
[00:02:23] So let's begin to refactor this component a little bit. This is gonna involve one of my favorite things in the world, which is deleting code. All lines of code or liability. The only way to have less bugs in your code is to have less code, or more tests, but all tests are code.
[00:02:42] So, we can just go ahead and get rid of this entire constructor. That'll be fun. We're gonna do the simplest version of this first, so let's actually go ahead and get rid of that as well. We'll have to change a lot of this, we'll rewrite it, reset. So effectively, if you think about a functional components, it's really just a component that only had a render method, which I kind of alluded to before.
[00:03:06] So now we say constant counter and that's just going to be a function, That will take some props out. We know this one got Max and step passed in. So I'll hold onto those for a second. I'm not using them immediately. And so we know that in this case.
[00:03:35] Now this'll blow up right now cuz I don't have a count or this .increment or this.decrement. But that is where we start to see the hook kind of come in. So I could say, const count and I'll talk about this syntax in one second, let me just get it in place.
[00:03:51] React.useState. So instead of function component which should have no concept of state or didn't 13 months ago and magically does now, we'll give it a default value is the kind of first thing and you can kinda see the hint from VS Code saying it's the initial state. So, I get back this array and the first item in the array is the value.
[00:04:13] And the second one is a function that allows you to set the value. So I could say something like increment is, Set count. Count plus one. Decrement is count minus one, and then reset, SetCount to zero. Now I don't need this here. So we can get rid of those.
[00:04:57] And so all of that component, we have a for, with the methods, and the binding of the methods, and the constructor, and pulling stuff out of the state object, it's all gone. Let's just flip over to make sure I didn't make any silly mistakes. It increments, it decrements, it increments, it resets.
[00:05:18] So it's a much simpler, cleaner syntax. And we're not worrying about event binding, we're not cuz I've been to that one before. It's kind of just pure in that sense. Now, let's actually begin to play with this a little bit. Let's see what happens, let's try some of the experiments that we tried before.
[00:05:38] So we'll go in here, and let's call it three times. And we'll do a console log here. The kind of first two experiments in our pop quiz that we did before. Let's see how it behaves this time. Does the same thing each time. So we know that is not dissimilar from the one that is asynchronous and two that is queuing things up.
[00:06:08] Again, there's no binding. We don't even reference this, there's no constructor. Great, the other thing is, similar to this .setState, it will also take a function. There is a difference, though, if you just wanted to do a clean refactor here that we'll talk about in a second, but let's just verify that this works so you believe me.
[00:06:32] All I wanna do right now is earn your trust. The subtle difference is while the last one took theoretically the state object in its whole and all of the props, this just takes that one piece of value. It's not a full object, it is simply a number. And it does not get the props as a second argument.
[00:06:52] So you can't do the stuff that we did with Max and step inside of the function itself. So for this, if I just want an increment, I could do what I did before. I'll just call Inc since I have now a function called increment. I can pull that out as I did previously.
[00:07:15] But since I don't have access to the props that are getting passed in, I couldn't do Max and step in here. Because it's outside of that function, so I cannot do that. So it's a little bit more limited in that sense, which is kind of a bummer but that's life.
[00:07:33] So we could write some of the functional code in there that we had before. But let's also just verify our other hypothesis. All right, we saw if we just said the value three times, it only incremented by one. What happens in this case if we use a function?
[00:07:51] It goes up to three. So, some of the behaviors are different, some of them the same. This is important when you are choosing to refactor it. Now, remember before I said like, hey, I'm gonna see if it's hit the max. If not, I'm just gonna return. And I put a hint in there like we're gonna see this again later.
[00:08:10] Let's see it again later. So the setCount or c. And we'll say if, C is greater than or equal to max. I don't have to do this .props or props on max cuz this is just simply passed in like that, we'll return and if not, Cool. So it should go 5, 10, 15.
[00:08:43] Cuz remember, it was 5 and 15 before, 15, explosion. Before, with this .setState, it was collecting those objects, it was merging them all together, and it was figuring out what changes it needed to make that large state object. Here, it's just a primitive value. So if you just take that code wholesale, and move it over, you'll notice I didn't even get an explosion error.
[00:09:06] I just got a subtle thing and then a counter that puts a big number on a page. We saw it, but for the more subtle and tricky parts of your state, There goes your afternoon. Hopefully just your afternoon, that comes to the point we get really embarrassed showing up to stand up every day going like, still working on that ticket?
[00:09:26] I was just gonna do a refactor and then I didn't store it in Git, and so here I am. [LAUGH] That subtle difference, so here we do need to return the value. So now, it actually does the thing that we want. And so that, my kind of warning is if you don't fully know how these work, most of the time, you're fine, as long as you 80% understand, you're cool.
[00:09:48] But as you start to do some of the trickier things and you start to refactor, the subtle differences in between the two might getcha.