Lesson Description

The "XState Store" Lesson is part of the full, State Management at Scale in React & Next.js course featured in this preview video. Here's what you'd learn in this lesson:

David demonstrates using XState Store for state management in React components. He also explains using atoms for managing state that can change freely, highlighting how atoms can be used alongside stores to provide fine-grained updates and reduce unnecessary re-renders in components.

Preview
Close

Transcript from the "XState Store" Lesson

[00:00:00]
>> David Khourshid: I'm going to demonstrate like these two libraries, or, sorry, these two types of libraries, by showing you one library actually. And so we're not going to be talking about XState, but we're actually talking about XState Store. Just because it is possible to use both of those approaches inside of XState Store.

[00:00:22]
If you've used Zstand or Jotai before, it's going to feel very familiar. So I'm using XState Store just to demonstrate the concepts. So we're going to first import Create Store from XState Store. And then here's what this looks like. We have two different types of things. We have the actual state that's inside the store.

[00:00:47]
And so in XState Store that's called context. So let's make a simple example like account. And then we have our transitions, which transition that state. So we have increment, and this is actually just a function which takes in the context and it takes in the event. So let's say that we have by and we want to increment it by some number and then we will just update the state so we spread the context in there.

[00:01:22]
And this is exactly as you would expect. The cool thing though is that XSTATE Store was built so that you have type inference. And so you don't necessarily need to say these are my actions. This is what the context looks like, because by default it can just infer those values.

[00:01:40]
And so with a store, you could subscribe to it. You could say store.subscribe and you could grab that context and then you could send it events, just like you can with useReducer or with xdate. But there's also a simpler way to do it too. We could do store trigger and then type dot increment and then you just pass in the payload over there.

[00:02:04]
And what that's going to do is that's going to log the incremented value. So that's the general idea of what a store is. It's a container of states where you update it indirectly via actions or sending in events just like that. Now, how do you use this in a react component?

[00:02:30]
So one interesting thing about stores, whether you're using Zestand or XState Store or a similar library like Redux, is that you can either pass it in through context or you can have this be standalone in something that you export. So let's say that we have a. Let's export a default page and we have a button that's just keeping track of the count.

[00:03:00]
So we want to subscribe to the count. So the way we do that, instead of using use date, we would grab the count from use selector. So we're going to grab use selector pass in the store and then we could read the counts directly from there. The reason that this is useful is because use selector is only going to re render this component when the count changes.

[00:03:26]
So you could do something like count greater than 10. And this is just a boolean value that's not going to re render every single time the count changes, but only when this value changes. So it's going to probably be false until it reaches that number. And in fact, let's try this console.

[00:03:52]
We're going to count the re renders over here. We're not using strict mode, so this might run twice, but and then we're going to show the counts over here counts greater than 10. So now if we go to local host exercise libraries, use clients [LAUGH] that gets annoying after a while.

[00:04:26]
So we have this button where we're not showing the count true false. Okay, so you see it changed to true. But the real question is how many times did it re render? Which I forgot to show you. So I'm going to reload this. So once you click increment, it's actually not re rendering at all until that.

[00:04:53]
And of course it rerenders twice because of react in strict mode, it's going to run the component twice. But you could see that no rerenders actually happen until that value actually changes. So that is a demonstration of using a store. Now, what about atoms? So atoms are a little bit different.

[00:05:19]
Like I said, atoms are something that you should use when the data can change freely, like from an external source. So let's say that I want to control this count using an atom instead the way that I would do that. And again, this is very similar to other libraries that will do the same thing.

[00:05:39]
We'll have const counts atom and we create an Atom. Oops, just a normal Atom with a value of zero. So now instead of using a store, we would just set the atom so we would count atom set. We don't need to get it. We could just get the value over here.

[00:06:04]
This is just value plus one. And then we could go ahead and log that count over here. But how do we get the count with xstate store, it's exactly the same way as you would select a value from a store. So we would say const count equals use selector.

[00:06:24]
We pass in the atom and then we could just, we could just give the value just for demonstration purposes and so you're going to see that this counts. Yeah, there we go. So now it just increments. And if we want to do something where you know, we want to see if it's greater than 10, then we could also see.

[00:06:56]
Let's also check the re-renders too. So you see there's no rerenders until it actually goes to over 10. So this is one of the key benefits of using these third party state management libraries, whether it's XState Store or different libraries, is that you can really reduce the amount of RE renders you have and you can make it so that you can say that components only care about the data that's relevant to them so they don't need to re render every single time any part of the state changes.

[00:07:36]
So that's a useful part of using either stores or an Atom-based approach is you have those fine-grained updates. Okay, so are there any questions on this topic?
>> Speaker 2: I guess I'm trying to think of the use case for Adam particularly because I'm like, I don't know, I was like stuck on the idea of like with the store of like, okay, you're bulk buying and once you hit 10 bananas or whatever in your cart you're doing a 10% discount or something like that.

[00:08:09]
But the idea with the Atom approach be more so of like our whole shop, it's like a flash sale and it's like you're constantly trying to get like what is the discount or something like that where it's coming from anywhere. Or what would I guess be a. Better.

[00:08:27]
Use case of Atom?
>> David Khourshid: Yeah, so a good use case of Atom would be just that. Let's say that you have something that is subscribing to store updates and then. Or like a shopping store update where it's like hey, no, there's a flash sale on this thing. And then you would just update that Atom directly or you could just do it as an event in the store.

[00:08:49]
But the idea is that that little piece of information sort of lives on its own. Like that flash update from a store doesn't need to or sorry, let's call it a shop. The flash update from a shop, it's not really related to the core data. So it might just be standalone in an Atom that you are updating from somewhere.

[00:09:08]
So we might have this hook like const use Flash sale and then you know, you would have some const Flash sale Atom and you might even instantiate this outside of the components where you're like set interval and then you know, you have whatever math dot random is greater than 5 sale no sale.

[00:09:41]
You know, something like that. So all of that logic lives outside. And then you could use that flash sale Atom and just. Yeah, so actually for instance, like let's say that we have account over here and this is the number of bananas that you want. So just call this bananas.

[00:10:06]
And so let's say that you want to increase the number of bananas. And if there is a flash sale, actually I'll just put this over here. But we actually want to select that. So const flash sale, we do want that. And then we want the counts of bananas.

[00:10:29]
So bananas and then we want the total value. So again this goes to lessons that we talked about before, which is deriving state. So we say const total price equals. And then flash sale equals sale bananas times 0.05, otherwise each banana is a dollar which is like Miami prices for bananas.

[00:10:54]
I don't know. So let's see. Flash sale equals sale. Should say no sale. And then this value isn't relevant. Okay, yeah, let's actually try this out. So again we have our total price and we have an external keyword being external data source, where it's just updating this, you know, this flash sale.

[00:11:16]
And so we could say H1 make it big. That's not what I. Okay, so you know, we might have a flash sale and then we want to show our total price over there. So now we'll go here and let's zoom in a bit. So there's a flash sale.

[00:11:46]
But now when there's no flash sale it sort of changes number, but you get the idea. I don't know why we don't have a banana emoji in there, but actually I'm glad that you mentioned that because right now we're combining. Let's do this. So instead of account atom we have account store and we're going to just increment that by one.

[00:12:13]
And so instead of this, we're just going to read that from the store. You can combine at least in xstate store you can combine stores and atoms together. And you could either do it like this or that changing value itself can be an atom. So we could say, let's just say yeah, everything is outside.

[00:12:35]
So we could just say const total price atom equals create atom. And then we're actually going to pass it in a function. And so we are going to just return. And this is so new that Claude has no idea what's going on. But we could say store get context bananas times oops wherever the times thing is and then flash sale item dot get if it's a sale then multiply that by 0.5 otherwise multiply that by 1 and then now in instead of this total price we could just select it directly from that total price atom that we have.

[00:13:24]
And so actually this shows you that we don't even need that selector anymore which might save us some re renders but now you could see that we're combining those atoms and come on flash sale there's no flash sale. There we go. And so you could see that price changing based on that.

[00:13:48]
So that's another benefit of using atoms is that you can combine them and so you could do things like that where it naturally or it innately handles the subscriptions and you know, things like that so it will subscribe to both the flash sale item and this store. So that's just how we can make state a little bit more convenient.

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