Check out a free preview of the full State Modeling in React with XState course

The "Component State in React" Lesson is part of the full, State Modeling in React with XState course featured in this preview video. Here's what you'd learn in this lesson:

David describes software modeling as knowing how an application will behave at any given time. A React component can model its state with the useState hook, however, the logic can get complex when there are multiple state values to manage.


Transcript from the "Component State in React" Lesson

>> Let's talk, firstly about software modeling. Software modeling is an old concept, and thinking about software modeling can conjure thoughts of UML, if you're familiar with that. But we're going to be looking at it in an abstract way. Basically, when we talk about software modeling or state modeling, we're talking about defining how an app is supposed to behave at any given time.

Now, what I mean by behave is, when an app is in a certain state, there should be certain events that can happen in that app. For example, if you're on the checkout page, the user should be able to fill out an address field and a billing field, and maybe click next, or maybe go back a step, or just do any of those things.

Now obviously, there's things that a user should not be able to do too. For example, if you're on that same checkout field, the user should not be able to, for instance, submit a payment without entering credit card details, or something like that. So the way we do this currently, or at least in most modern web projects, is we just start with code.

And let's go ahead and go into our scratch pad and see how that sort of looks. By the way, the scratch pad, you can find at scratch/index.js, and then you could play around with this however you want. In this scratch app, we have just a sample alarm, and I will just go to the root directory to show you that.

And it shows the current time and a toggle that doesn't work. Right now, it has data-active. If I take that off, you'll see that now it's not active. So let's say that a simple task was, we want to toggle this from off to on. The typical way that a lot of React developers would tackle this problem is, they'd say, okay, we need a piece of state.

So we would say const [isActive, setIsActive] and then we would use the useState hook. And so we'll start with false, and then we put that in this data-active property. By the way, this is a property that the CSS file that I have over here recognizes. So we could use those data attributes to change whether it's active or not.

If it's not active, it's gonna be white and to the left. If it is active, it's going to be blue and to the right. So we could say data-active is isActive or undefined. Now, just a note about data attributes. Putting undefined is actually important, because if you forget to do that, this will take that false value and translate it to the string false, which we don't want.

We want this data attribute to just go away completely. And so we see it works here. If we change this to true, it will toggle on. Now, let's say that we want the behavior that clicking this alarm should change it from off to on. So we could say onClick=, And we could set isActive to the opposite of whether it's active or not.

Again, this isn't the way that that you're going to see in this workshop. But it's the way that a lot of React developers would start. So you can see that this does work, it does go between not being active and being active. But let's take a step back here, because we're representing the state of this alarm toggle as a boolean value, essentially.

We have either it's true or it's false. So we have true or false for isActive. But here's the thing, boolean values are great for if you have something that is either truthy or false-y. And I do recommend that you use them if that's all that your app needs.

However, what if we have another state? Like for example, what if we're setting this alarm, and we want to persist it to a database? Or just save it in the cloud, so that it's available on all of your Android devices, so that all of the alarms go off at once to make sure you really get up in the morning?

Then we need some sort of other state where it's saving, and we can't represent that in a boolean, right? So yeah, so how do we how do we reconcile that? Well, we could use what's called enumerated values. So instead of true and false, which limits us to two, we want to be able to potentially add more states.

So let's just try that. Instead of having a boolean of isActive or setIsActive, I'm going to change it to alarmStatus, or actually, let's make it status for short. And then we have setStatus, and we're going to use states. Let's talk about what the statuses could be, it could be either inactive, pending, which means we're waiting for it to save, and we'll fake that in a minute, or active.

So we're gonna just set this to inactive for now. And so now, our logic is gonna change a little bit. But you're gonna see it's about to become a lot more explicit. So data-active is going to be, if the status is active or undefined. And onClick, we're just gonna set isActive to pending, or sorry, setStatus to pending.

We're going to useEffect, and we're going to change the status after, say, two seconds. So we're going to, or if status is pending, then setTimeout. And we are going to setStatus to active, and we're going to do that after two seconds. So let's go ahead and do that.

And so we could do something like, let's just do here for now, opacity, we're going to say status is pending, 0.5, otherwise 1. So it's going to fade out when it's pending, otherwise it's going to show it full. So when we click this, you're going to see, it sort of fades out, and then after two seconds, it goes to active.

Now when we click again, it should go off, but it sort of just keeps going on. And so this is where things get confusing, because even though this is a better way of modeling our states, we no longer have these confusing true, false, saving. We now have this enumerated, it's either inactive, pending, or active.

We have that, but we're still setting it directly. And so that's why when we click, we're setting status to pending. But now we have to add a check here where, if status is active, we actually want to set the status directly to inactive. Else, setStatus('pending'). Okay, so let's try that again.

We click here, it's pending, it goes to active. And then when we click again, it goes to inactive. And then we could repeat the process again, so, All right, so we have our three statuses, inactive, pending, and active. And already, this is a good first step to just being really clear and deliberate with what states our app, or in this case, our components can be in.

But there's still one problem with this. Look at these if statements. We have, if status is pending, only then do we set this timeout. And then you also have to think about cancellation. So we didn't do that in here, but we could do that with const timeout = setTimeout.

And then in React's useEffect, you return a cleanup function which clears that timeout, and then that should work. But we also have some logic over here, where onClick, clicking it could do one of two things. It could either set the status to inactive, or it could set it to pending.

So basically, if another developer comes on the project and is trying to figure out, how does this alarm work, then they're going to have to look in multiple places. First, they're going to have to look at this useEffect. They're going to have to look at this and figure out, okay.

I guess because of this comment here, we have inactive, pending, or active. But if this was gone, now we have all these different places where we have to look in order to see what the possible states could be. And so that is the main question that I want you all to ask yourself when you're creating your apps, is what are the possible states that this app or this component can be in?

In this case, we have to look here, here, here, and even down here, okay, it could be inactive, it could be pending. Basically, we're looking for all these setStatus calls. And clicking does not do the same thing. So think about a real world device, one where you would press a button to toggle something on or toggle something off.

Do you think that there's logic inside of that button itself? There actually isn't. So a button in a real world device, like an electronic device, or even a physical device like a phone, you have a button here for volume, for power, those send a signal. And so that's the only thing that the button should be concerned with, is sending a signal to somewhere central that then decides what to do with that information.

Given the current state and the signal that it sends, or you could call it an event, it's going to change the state of whatever we're dealing with.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now