Goodbye, useState (PodRocket, alternate cut)
Watch on YouTube (LogRocket)
What is this talk about?
David Khourshid, founder of Stately.ai, joins us to discuss better ways to manage complex state in React applications. We explore the pitfalls of overusing useState, how discriminated unions and state machines improve app logic, the role of server components, and the growing importance of query strings and persistent state management. He also shares insights on modern third-party libraries, React’ (From the video description.)
“In this episode, David and I talk about hooks to use instead of useState, the problems with useEffect, the delicate balance between local state and global state, and how reducers and state machines can help solve some of those problems.”
“I'd like to say that like when you're doing things such as async data that's like a oneanddone type of thing but that's not always the case when it comes to dealing with async data.”
From the opening of the conversation.
Key takeaways
- In this episode, David and I talk about hooks to use instead of useState, the problems with useEffect, the delicate balance between local state and global state, and how reducers and state machines can help solve some of those problems. 0:00
- You can actually design your app logic around that and then from there you could determine is this a good use case for use states or useReducer or a third party state management library. 6:00
- I'd like to say that like when you're doing things such as async data that's like a oneanddone type of thing but that's not always the case when it comes to dealing with async data. 13:00
- The problem is that state concerns in an application are varied. 17:00
- I just this was just a vibe was that like the idea was that less and less data would need to be pushed up and shared in like this whole global state object and that was an antiattern. 29:00
Quoted from the transcript. Conversations include other speakers.
Full transcript
From YouTube auto-captions. Technical terms were normalized; some errors remain. 7,273 words.
0:00 Introduction
Hi, Elizabeth here, production assistant for the Pod Rocket podcast. Before we dive in, did you know that Pod Rocket is on YouTube? You can catch the full video versions of our episodes over on the log Rocket YouTube channel. Click the link in the description to tune in and subscribe so you never miss an episode. The default approach is I need to update states, so I'm just going to update states. But then the problem becomes why did the state update? And that typically becomes very hard to trace. So events provide the why. Hello and welcome to Pod Rocket, a web development podcast brought to you by log Rocket. Log Rocket provides AI first session replay and analytics which surface the UX and technical issues impacting user experiences. Start understanding where your users are struggling by trying it free at logrocket.com. I'm null and today I'm joined by David Cororshed, software developer and founder of Stately.
Here to talk about state management in React. In this episode, David and I talk about hooks to use instead of useState, the problems with useEffect, the delicate balance between local state and global state, and how reducers and state machines can help solve some of those problems. So, here's the episode with David. Hey, great to be here. Thanks for having me. Yeah, for sure. So, I think this talk is an interesting one. There's two main components. I think that the first you're kind of addressing foot guns people run into are problems. This problem state people get into where there's all this state flowing through an app and it's hard to figure out when renders are happening and what's triggering them and these like loops and all this stuff and you kind of get into some ways that can be solved. Why do you think it is that we are in this pattern where like devs so commonly find themselves in this kind of trap this web and like do you think that there's a fundamental problem here that is leading to this?
So the fundamental problem isn't I would say necessarily React itself. React provides the primitives. However, it is the way that we developers use these primitives. So first of all, use states seems just by the name like the go-to for state management in React. It's simple and there's this immediate gratification of okay, I could just put state in there. I could update it wherever I want. But there's this whole idea of easy verse simple. If you remember Rich Hickley's talk, it's easy to get started with ustate, but once you have more and more states and once you start mixing concerns of UI state versus app states, then you have this whole mess of use states and useEffects trying to work together and it just becomes very complicated where you'll have components with maybe 12 or 15 different use states all with varying relevance. So some could be groups, some others are not relevant at all and just becomes very hard to untangle once your app gets at a larger scale.
You go into some kind of patterns here that can be used to help solve various cases wherein a dev might end up in one of these pit holes. I feel like there's almost a fundamental tension here in that state feels like the simple base case like it feels very functional like it's very localized. It's easy to reason over. So then I feel like almost historically it was almost like there was back in the day it was like put everything in like external state management and then like bubble things out from there. But then there were pitfalls with that where then it was like okay but now I've got to like know where every like everything that's calling like a function that may end up mutating this global state. So that's like kind of tricky too. So there was like this push and pull of like simple local state and then pushing things up to global state with some management. And it feels to me that it's hard to prescribe something simple like to point developers down one path or the other.
Do you think that there is a good kind of barometer that devs should be looking for on like when things have gotten so tricky that like local state management and like passing props up and forth or back and forth like that has become a problem. There is a balance. Use states and useEffect and all these hooks they exist for a reason and they solve very real problems. And that's not to say that oh you should be putting all of your state in some external state management library or lifting it up to context with useReducer or any other sort of blanket statement like that. I would say that for example useState is very useful for UI facing states. So the states where it's controlling how your components render visually things like derived states and things like that. However there are also use cases where that just becomes very complex. So I think that it's sort of become an antsy pattern to just use states pretty much everywhere and it creates a lot of complexity. Yeah. Yeah. I feel that as well.
I feel like the common thread here is like often in these other alternatives you go through you're talking about grouping related data and putting things like in the query string like we get into this mode where you're often if something's using useEffect like that seems to be the point where it's like okay maybe is there something else we can do here instead of useEffect. Do you notice that at all? Do you feel that it's the case? If there's a lot of effects happening, that's usually an indicator that something may be a miss in the design of a component. For sure. Some of the hardest to debug problems is what I call a cascading chain of useEffects. I talk about state machines a lot. So, I call this specific pattern a Rube Goldberg machine where I'm sure you're familiar. It's one thing triggers another thing which triggers some downstream thing and then all of a sudden you have a very hard time debugging what caused the change in the first place.
And so that's chain is just a prime example of the kind of complexity caused when you're just trying to manage everything including side effect management and complex app logic with both the use states and useEffect. Yeah, at least personally, I've found that if I'm at the point where I'm in useEffect and that effect is triggering any further state management, I'm usually like, okay, now I'm in like the danger zone. But I often don't know where to go from here and I end up just going for a global store usually with some like mutation that can then bubble out more easily. Is that what you find yourself most often raing for or is there is it like it depends on the situation a little bit more? It depends on the situation. But also, there's a big thing that I feel a lot of React developers miss because as developers, our go-to is just, okay, which tool is right for this job? Okay, useState data is not working. Maybe we'll use a different hook or we'll use a third party state management library.
But I really encourage developers to actually instead step out and think about how your state should be modeled in the first place. So first determine where is your source of truth and depending on that like whether it's from the database or even from the URL which is sort of a big concept I talk about in my talk where the state might not actually need to live in memory but can actually live in the URL. You can actually design your app logic around that and then from there you could determine is this a good use case for use states or useReducer or a third party state management library. So I think that the missing first step is actually modeling the app logic and by that I just mean determine what's your source of truth and what are the rules around the state.
7:00 We could say if status is success we have our data
So basically in any given state let's say you're submitting a form what can the user do what can happen you might be getting data in submitting data out the user might be able to click certain buttons or fill out certain fields just modeling that out before even jumping to code. I want to kind of circle back to like query string and local store and those kinds of things, but on this problem specifically, you touch on like discriminated unions like kind of ways of actually encapsulating these I don't want to overload our terms here, but these kind of like complex states of being that like a given component can be and that we all like often end up trying to mangle together and suspend across several variables.
Can you go over that a little bit briefly and what are the primitives there that like may be helpful to capture that complex state that's living across multiple variables in certain components? Yeah, so discriminated unions are great. It's probably one of my favorite type features or TypeScript if you're using TypeScript. With a discriminated union, you could essentially say that an object is discriminated based on a single property. And for example, that property can be status. So I'll give you an example. Let's say that the status is loading like you're loading a form or the status is idle success error or maybe it's referring to a specific page. Now when status is success you could say my data whether it's user data or whatever is definitely defined. It is in there. We don't have to do any type coercions or anything. We could say if status is success we have our data.
If status is loading then we don't have our data because in so many code bases first of all I see that all of these are mixed together. So you do have to do some unnecessary defensive programming and checks like is this data defined even though status is success or we have some boolean is success true and that adds to the complexity because now you have unsafe TypeScript mixed with just a bunch of boolean variables and floating use states. So that's why I think both grouping related states and using discriminated unions are extremely useful. And so th this I would say is the first step to thinking in terms of a state machine without actually having to use a state machine. Let's talk about this kind of state machine concept. It feels to me that this these kind of discriminated unions particularly when used as a means of capturing like the status of a given component because I feel like that's how I most often see them used, right?
That's how we think about them at least. It's like this hook is or this component is in like one of five modes like we're loading, we're submitting or like it's in an invalid state or a valid state like oh like these different modes and I often see that. Do you think like that is happening often enough that maybe that this should be some kind of like more intrinsic like primitive like there should be something in React to capture this because I feel like this is where I always see this is it's like the current kind of status of a given component is in this union but for each one of these the developer is tasked with like determining that needs to happen and setting it up.
Do you think that's a common enough pattern that like it should maybe be abstracted a little bit? I think so. And recently there was a new React API where I tweeted about it maybe a few weeks ago, but it actually did have a oh it had something to do with animation and it was actually using a string enum. You can't see it, but I'm putting quotes because JavaScript doesn't have native enums or anything like that. But it's basically using a string to specify the status which I think is really great and it does eliminate a lot of that boolean mess. Now there's other hooks too. such as use action state which will reveal a for example an is pending variable and so again this might be going against what I say where it's like hey try to use stringing nooms instead of variables but I think things like is loading etc are really good when it's derived state the problem is a lot of developers use that as a source of truth and then you have this boolean explosion where you can't really guarantee that is loading is true and is success is false like you're like Oh yeah, those could technically both be true, but they shouldn't ever be.
With stringy nooms and like these discriminated unions, you could actually prevent those from ever happening. Do I think it should be built into React? I think that React is on that path already, which is good. And there's libraries too like React query that also have this status that they reveal. You could still use is loading, is pending, etc., but they also reveal a status string that you could use as well. I guess on that note of the direction of React. Do you think that React server components help solve this problem because in your talks you could go over how there's like kind of an intrinsic state layer added there, but it almost feels to me like this is just another layer that could be going wrong or adding to this kind of like web of state and rendering and all this stuff.
12:00 I think server components are very good for that initial I…
Do you think React server components make this simpler or more complex? When we look at how React developers typically fetch data with useEffect and stuff, that alone contributes to a lot of complexity because they think, oh yeah, we could just shove it in a useEffect, have three or four use states managing the data, whether it's loading, etc. And you could imagine just all that boiler plate, just how many lines of code that adds to a codebase. So with React server components that eliminates so much of that complexity already, you have suspense. So yeah, you do have this innate way of saying this data is loading because we have a suspense boundary. We could show a spinner or something and this data is loaded from that server component. So we could actually show that data on that component. So I think just for the simplicity alone of being able to load async states before a component is rendered to the front end, it's extremely useful in that regard and it does eliminate a lot of those state management problems that comes with async data.
Are there any new kind of state management problems that you've encountered in particular that server components introduce by like by virtue of having this like a page kind of rendering in two places or in a server and then having to be dealt with in the front end? So I think server components are very good for that initial I need to get data and show it to this component. However, when it's actually needing to fetch more data then that's where it does get a little bit tricky. There's some framework specific APIs for that where you could for example revalidate a page etc. But I'd like to say that like when you're doing things such as async data that's like a oneanddone type of thing but that's not always the case when it comes to dealing with async data. We might for example try to subscribe to something or get things over time. And that's why we have to invent solutions for things like a lot of people are building AI powered chat apps and so that has to stream data in but even besides that there's a whole host of other problems where we have to subscribe to something periodically or sync some local state with some external state and then that just gets really tricky.
So server components definitely do not sell for that major use case and very common use case of you need to load data and show it. It's really great for that. I'm thinking of cases here. Yeah. Where there's like some kind of list initially loaded and then on the client we're like adding more items over time and then there's maybe some filters and stuff that you're like trying to apply to the server load on first load and then also the client load on subsequent loads and those are maybe an apparent component that you're like trying to keep in state or in sync over time. That's where React query is still king there. Yeah, I agree. Yeah, I think yeah, like that's probably as good a good a segue as any to talk about libraries a little bit. I do want to touch briefly, you mentioned like query string logic a second ago and how devs aren't reaching for it quite as much anymore or it gives one anxiety when you're on a page I'm afraid to reload because I don't know what's going to happen.
I've found this as well. But to me that almost seems like a different problem. Again, it could be it's can be local storage or query string or whatever it may be of like state that is core to an app not persisting for whatever reason. Do you think that this is like actually kind of part of this complex rerender problem that we're talking about or do you think this is more of just like a separate problem of devs not considering when a page may not just have everything it needs in memory like of reload? Yeah, I think that using the URL for state is extremely underrated and unfortunately with the way that we normally develop apps, we just don't think about it. So yeah, that fear of if I reload the page, all of my data is gone or I lose my filters and settings and whatever, that's a very real fear and that's why Remix makes it a little easy to use the query parameters. But there's also libraries like nux and uqs which also makes that very easy and I believe that tanstack search and tanstack router tanner does a lot of amazing things but that also treats the query so the URL search parameters as a first class citizen because it is important like the URL is a natural states container talk you know just going earlier to where does the source of truth lie so yeah I think that more and more developers should use it.
Yeah, this kind of brings me back. It's been a while since I've gone down this path, but it does make me ponder it a little bit wherein like again there was a time when everyone was using Redux and everything was being pushed there and then people were like what if we just serialize the whole state and stick it in local storage and so it's always there and then like whenever you render you pull that whole thing out and I feel like this was the problem that we were trying to solve at that time. Do you think that there's anything to that notion? Is that like something that could be considered? And have you seen any tools that kind of go this direction? So the problem with that and like with early Redux in general is that it's trying to prescribe too much where it's like no just put all of your state in global state and obviously you could sync that with local storage or what have you.
But the problem is that state concerns in an application are varied. So we were talking about URL as a source of truth for state. That's very true. You could also have state in like coming from your database. You could also have in-memory states where it's either global shared between components or specific to single components or at least single components within a hierarchy. So the component and its children and descendants. So there really is no one-sizefits-all solution. And that's something that I want to emphasize. So when you think about oh let's just serialize the entire application state and put it to local storage that might not be feasible for the reasons that I just mentioned because when apps grow to a certain level of complexity you are going to see a mix of those state management solutions and it's a necessary mix like you will get more complexity if you try to shove everything into one place.
So that's just a reality we have to accept and avoid complexity by just knowing the proper patterns to choose. Yeah. Yeah. Agreed. Again, like back to an example of a list of items that may be filtered on the client. Like it very much feels like the filters should probably exist locally and be persisted locally, but then like the data should always be being fetched dynamically without persistence. Have you encountered any libraries or thought about this problem where in like it's easier to store state in the query string or in local storage or wherever it may be? So that property of having it persist is a little bit more top of mind versus something that has to be kind of like consciously considered by the dev every time new state is added. So Nux handles this problem nicely where it's not automatic. You're essentially replacing useState with useQuery states. But I would say having that explicit is going to be a good thing anyway because the problem with making it implicit is that you might have state that you don't want to show up in the URL or hidden state or something like that and then now you have to provide options for filtering that down.
So I prefer to be more explicit where this used to be sort of a hot stake or against the grain sort of way of thinking in the past where it's like why write things verbosely? why I write things explicitly when I could just have the library do all of its magic for me behind the scenes. But nowadays with AI powered coding assistance, it does all that boilerplate for you. And it is better to see those explicit things up front. So, you know, replacing state with useQuery state, adding things to local storage when needed, knowing exactly what's going in and coming out of local storage than just having some library magically abstracted away as a black box without you ever knowing what's going in or out. I think like explicitness and devs. Devs seem to be minding it less and less. Let's talk a little bit more about this kind of just third party state libraries in general.
I feel like we've been skirting dancing around this a little bit. This was almost easier before when there were fewer options. I feel like there's a lot more kind of players in the space now. When do you think devs should be considering using a library at all versus to your prior pointers and just make it explicit, build it yourself? Like how do you weigh those two options? Like when do you recommend devs reach for a library? Yeah. So there's a spectrum of course you start with useState for local states and component specific state and then once your logic has more specific rules to how the state should be updated that's where useReducer comes it comes into play really well and then if you need to share that state now you might be considering okay let's put useReducer into context so that it could be spread between multiple components but then number one you're writing a lot of boilerplate and probably reinventing a few wheels and secondly you have performance issues too and so this is what libraries solve and sure there might be a lot of options in fact I contribute to some of them I have XState and a newer library called XState store and of course there's many popular ones like Redux Zdown Jotai recoil etc but I would say that these libraries really come in two flavors or you could think of it as a quadrant but just to simplify they come in two flavors the first one is direct state updates.
So these are state where you could just update it direct. There's no rules. It's like Joe just update the variable directly have that propagated everywhere else. And then there's the indirect state updates where it's basically event or message based. Essentially you're providing an intent. You're like or an event. So the user submitted the form, the user changed this field etc. And then based on that you're not directly updating state. instead it's indirect and the logic within the store says okay given this event I know how to update the state according to my rules so that's what I'm going to do and I think even though that's a little bit more verbose it's more explicit and it is a lot safer to do it that way so the libraries fall into one of those categories and yeah so I would say just choose the option that is most comfortable for your team something where everyone can agree how to use it properly and be most effective with it.
22:00 You have to have a better way of saying either memoizing…
Yeah. Yeah. I feel like there's two data points that kind of weigh into that decision is like usability and like the shape of your app and also performance. Have you found that there's like either of these kind of options? One that's more like reducer like where there's a function that's explicitly defined by the store versus like directly mutating it where needed. Have you found either of those are more performant or lead to performance issues? It really depends on how you use it. So with the store-based approaches, you have to use a selector and the selector is basically just grabbing a slice of that state and then you might need to use comparators because let's say you're filtering a list that identity is going to change every single time. So now you have to have a better way of saying either memoizing that results based on the parameters for selecting it or for filtering it or using a comparator or something like that like shallow equal something like that.
So there's that consideration when using stores. But with atomic states, so a state based on signals or atoms, you'd have that automatic since they deal with much smaller pieces of data, you'd have that atomic like just performance benefit where only something that cares about that specific atom is going to update even though other atoms might be changing because you're not changing a large store. Instead, you're changing individual pieces of data that you could individually subscribe to in a fine- grained way. So, it's not that one is faster than the other. It's just that one requires more manual tuning for performance, whereas the other one deals with smaller data. So, it avoids that problem. But like, if you're dealing with larger data in a store, then you can't really just shove that all into an atom because then you'll have the same problems. I found I've most often encountered this where I have a list of components and then each of those like cares about a specific slice of an array, right?
24:00 I just this was just a vibe was that like the…
It's like oh like this is number whatever seven or the one with this ID, right? And like it needs to then prescribe wherever changes to that are coming from and like the two different modes of looking at that as you described do feel like very different and how I need to like filter and look at those items and subscribe to updates. But I think that you put it nicely there and that is the part of it that thinking about how you actually like filter and look at the data I think is the thing that dictates probably which one of those two paths is going to be kind of less painful for you to use long term and then figure out how you want to mutate it from there.
In the talk you kind of talk about how the events driven approach kind of has a lot of just intrinsic benefits back to your point of being explicit and traceable. Do you think that devs are going that route less often than they should be and reaching for something where they can do direct mutations and it's causing problems? I think they do go for it less often because the default approach is I need to update states so I'm just going to update states but then the problem becomes why did the state update and that typically becomes very hard to trace because that updated state might come from props which might come from some sort of centralized or decentralized state management and then you have no idea where it originated from.
So events provide the why and I think that is very important even if you're just using it for console logging or saying okay what series of events led to the state being in this potentially inconsistent state so that I could start to debug and go based on that. You can't even trust things like a call stack because things might be async. Things might not happen exactly as you intended. And for example, for React, if you do one state update, it doesn't happen synchronously. It's batched and then it happens like on the next render cycle, etc. So, you can't just go back in the trace and see which function ended up changing it. And that's where events really fill that gap. They give you the reason why things are updated, but also they allow you to change the logic itself. So you could send the same event and have the logic change and understand that okay, yeah, this same event will now do something different.
It's because my logic changed, but the intent is still there. I know exactly why this data changed. It's because this event was sent. I feel like we're telling the same story in a couple different ways here in that like useReducer is nice and like eventbased mutation to global the global level is also nice because you get this traceability and you can make these more complex changes. I feel like when we were in old like classbased React that was the thing you just did like those you always tended to reach for. Do you think that this was less of a problem before and we've painted ourselves into a corner a little bit with you state and that being the hook that is the default? I think it was somewhat less of a problem because man I remember way back then you used methods for all of these updates and so methods function. Yeah. Yeah. Methods are essentially those events in a way and again I'm putting hand quotes because you could conceptually think of them as the same sort of intent driven thing where you know you say I want to do this and based on your centralized logic you would either change the state or do something else or maybe reject that just whatever.
So yeah, it was less of a problem and hooks unfortunately do make it a lot easier to just directly update the state. If you were like redesigning React today or were in those rooms when the hooks were being discussed, would you have advocated for something different or would there be any kind of subtle changes to how that state management kind of was prescribed? I don't know how much I would change. I really like for example the way that solid does things with signals. So if I wanted to really allow developers to have individual pieces of state that could be changed from anywhere, then I would definitely use more of a signals approach because that's it's just a really good use case for it and you avoid a whole class of performance issues that way. But for things where you do want that indirect state management, you want that centralized logic, I would move closer to something like spelt stores.
And I know that React is considering this innate idea of a store. It's really a huge missing piece in React that other frameworks do have either as a blessed third party library or something built in like spelt stores. that's the one thing that I would strongly push for because the idea of a store as a single thing like a single entity now you could take that share it around in props put it in context and so you have local state that you could manage with it global state shared states you could wrap it and just going back to what we talked earlier sync it with local storage or the URL like just the idea of a single store where you could send events or subscribe to state updates it's extremely useful and that's something that I would have pushed for more.
Yeah, I feel like the React team had like they were thinking about this at the time, right? But I have to assume that it was kind like if devs need it, we have like external libraries, they can reach for it. And I yeah, I see the decision both ways. But part of me always felt that I like the reason and I don't have any data here. I just this was just a vibe was that like the idea was that less and less data would need to be pushed up and shared in like this whole global state object and that was an antiattern. That was what I was alluding to with my very first question when you and I first started talking. Do you think that was a thing? Like I just really felt like everyone was like there was a mo a moment everyone was like put everything up in the global because we're going to need it and then there was like oh no this is also a problem. Everything should be as localized and like functional feeling as possible.
Did you feel like there was ever that tension there nor am I inventing this whole history in my head? No, no, you're you're absolutely right. And it's a pendulum swing. There is the idea of all states should be local and atomic and whatever and just like very small pieces of data being represented in individual use states or whatever. And then there's this whole idea of no, you should have this single global store that's shared with everything. But the real answer is in the middle. So, first of all, having a single piece of global or single place for a global store is not really realistic just because there's multiple sources of truth. Again, we talked about the URL, the database, and then even different concerns within the app. So, let's say you have a an ecommerce app. The cart is maybe one concern. The items are another concern. The payment details are another concern.
You can't just shove that into a single reducer made of multiple combined reducers and treat it as one object because that's just not reality and you're going to make things more complex that way. In reality, it's in the middle. So you have probably multiple stores, you have some component local state, you have URL based state. Like I said earlier, you have states coming from everywhere. Yeah, I think that's tricky. As a dev, I agree that it does always feel like a balancing act. And I feel like most people practically feel that as well. When you're looking at these kinds of things, working on the tools that you work on, how are you balancing the pendulum of like modern opinion on maybe how much should be global versus local compared to what you think is actually the correct kind of architecture to generally prescribe to users of the APIs of the tools that you're working on.
31:00 Thinking about those three things you begin to separate your data…
So the trick is modeling. It's not a specific tool. It's not even doing things specific to the framework. It's basically diagramming things out. And they don't necessarily need to be visual. I like thinking about things in three ways. First of all, the data. So, you could think of it like an entity relationship diagram. Like what is the data that I'm dealing with? How does it relates to each other? If I have a to-do app or something like that, where do all these to-dos belong? How are they grouped? What are the properties of each, etc. And then there's the sequence diagram that I would think up of okay what are the external parts of my application that need to communicate with each other. So I might have a to-do service or an authentication service and thinking about what are going to be my fetch calls etc for that. And then of course there's the state machine which just tells me I know it seems especially if you're not familiar with them state machine seems like such a scary term but it's just think of it as a single container of logic that tells you how your state should update and that's pretty much it.
You have states and then you have events that can update the state. That's all there is to it. So thinking about those three things you begin to separate your data and the services that you communicate with. And then from that data you derive okay this is the derived state that I need from that data that I have to show in my UI. And then you can make those clean separations where your derived state lives in the components. Your ephemeral local states lives in use states and then things that might be shared concerns can be in useReducer or a thirdparty state management library. And then things that might need to communicate with services or where the source of truth is elsewhere can be done with things like server components or useQuery or even the URL as states. Do you think that this demystification or trying to make it sound less scary of like the concept of state machines is that part of your value prop with Stately?
It is because I like to present Stately as a tool for thinking not a tool for oh you should be doing everything with state machines. It's just it allows developers to have that aha moment of oh wait like my state my app logic can be mapped pretty visually to these boxes and arrows or states and transitions and I could clearly see the different paths that a user could take throughout my app. I could see that when I'm in this state users should only be able to do these things when some part of my app is in this state. only these things can possibly happen and this is how the state is updated when those things happen. So it's just a clear visual mapping of what can happen in the application where developers might not be thinking about it or might just be waiting for a bug report from the QA team that they got into an impossible state and that's something that you want to avoid ahead of time.
34:00 Yes, I want to see first class support for stores
I want to ask one more question on if there's anything you'd like to see in kind of state management React 20. Is there anything fundamental you'd like to see as like a next step or generally the path forward just for this kind of state with React conversation? Yes, I want to see first class support for stores. React has external store but then they have a you're on your own figure it out yourself way of implementing it. But I really want them to have a first class way of doing that. Cool. Cool. All right. So, I'm going to get into our lightning round questions properly here. Server components overhyped or the future? I think they're the future, but with growing pains, they solve a lot of real problems, but the mental model shift is the challenge, not specifically the technology. Ah, nice. Yeah, agreed. Agreed. Do you trust AI generated React code for implementation? Yes. But for architecture, no. It's great at boilerplate code and not so much at other stuff.
It's like a really powerful junior developer. Is there one React feature you wish more devs understood? Yes, I would say useReducer. It's one of those ones where it's let's shy away from it. Let's not use it. But it's very useful when it's necessary. I feel like it's one of those things like actually just having derived state in the render like user it can save so much pain a lot or can at least delete a lot of code like we just don't need all this logic here. We can just do the thing. Okay, cool. How do you feel about context for state sharing? Is it a necessary evil or a solid tool that should be used? It's a solid tool used badly. It's great for dependency injection like themes, all of configuration, stuff like that. But it's terrible for when you're frequently changing the state. But again, React doesn't really prescribe a blessed way to do that. So that's why I'm waiting for stores and context is that unfortunate necessary evil for dealing with global stores right now.
Hopefully that changes in the future. Perfect. Cool. That's all I got for lightning round questions. Is there anything else you wanted to leave off with here, David? Or do you think we've covered most of what we wanted to chat about? Yes, if you don't know, I'm the creator of XState, which is a state machine state management library, but I also recently created XState store, which is very close to Zustand or you could think of it like a better used reducer, but also Jotai because it does have those atomic based state updates if you want to use that. And so this is something where I really think that if developers want something simpler than XState, they should check out XState store. I'm a big Zustand user, so maybe I'll have to explore a little bit and check out some other tools. I've got a couple projects I've been in this mode of. This is all going to be global state, so I need to trick some new stuff out. But anyway, this has been a pleasure.
Thank you for coming online, letting me pick your brain a little bit, David. Thank you so much for having me. Of course. Take it easy.
Related talks
-
useWat
React Rally 2023. 32:41, 2.7K views -
useWat² (with Jenny Truong)
React Miami 2024. 27:55 -
useWat
React Alicante 2024. 33:06 -
useState Is Over
PodRocket (LogRocket podcast), 2025. 42:01, 1.2K views