Copy of David Khourshid - AUDIO EDIT === Noel: [00:00:00] Hello and welcome to Pod Rocket 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 users are struggling by trying at free@logrocket.com. I'm Noel, and today I'm joined by David Korshe,~ uh,~ software developer and founder of Stately Here to talk about his talk. Goodbye you state. ~Uh, ~welcome to the show, David's. David: Hey, great to be here. Thanks for having me. Noel: Yeah, ~for sure, ~for sure. So I think the, this stock is an interesting one. There's two main components. I think that the first are kind of addressing,~ um, kind of~ foot guns. People aren't into or problems ~this, this, ~this problem state. People get into where ~there's all these, like state,~ 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 kinda get into some ways,~ um,~ that, that can be solved, ~I guess. Do, do you like,~ 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, is leading to this? David: So the fundamental problem isn't, I would say, necessarily [00:01:00] React itself. React provides the primitives, however, is the way that we developers use these primitives. So first of all,~ uh,~ use dates seems, ~you know, ~just by the name, like the go-to for state management in React. ~You know, ~it's simple, ~you know, ~and there's this immediate gratification of, oh, okay, I could just put state in there. I could update it wherever I want. But there's this whole idea of easy versus simple. If you remember Rich Hickey's talk. ~Um, so. It's, ~it's easy to get started with you state, 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 use effects trying to work together, and it just becomes very complicated where you'll have components with. Maybe 12 or 15 different use dates, all with varying relevance. So some could be groups, some others are not relevant at all, and ~it, it, ~it just becomes very hard to untangle once your app gets at a larger scale. Noel: ~Yeah. Yeah. So again, like you, ~you go into some kind of patterns here that can be used ~to, ~to help,~ uh, like ~solve [00:02:00] various cases ~wherein, ~wherein ~like, you know, ~a dev might end up in ~one of these, ~one of these,~ uh, kind of pit~ pitholes. ~Um, but like, ~I feel like there's almost ~a, ~a fundamental tension here and that ~like.~ ~Use, uh,~ use state feels ~like, ~like the simple base case. Like it feels very functional, like it's very localized. It's easy to reason over. ~Um, ~so then ~like. ~I feel like almost historically it was almost like there was, ~you know, back, ~back in the day, it was like put everything in like external state management and then like bubble things out from there. But then ~like ~there were pitfalls with that where then it was like, okay, but now I've gotta like ~kind of ~know where every, like everything that's calling like a, ~you know, ~a function that may end up mutating this global state. So that's like kind of tricky too. So there was like. ~This, ~this push and pull of like simple, local state and then ~like ~pushing things up to global state with some management ~and, and, ~and it feels to me that ~there, it's,~ it's hard to ~kind of ~prescribe something simple like ~to ~to point developers down one path or the other. Do you think that there is~ like an, like~ a good kind of barometer that dev 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. David: There is a balance. ~So there's, I mean, ~use states and use effect and all these hooks. They [00:03:00] 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 use reducer or any other sort of blanket statement like that. I would say that, for example, use state is very useful for UI facing states. So the states where. It's controlling how your components render visually,~ uh,~ things like derived states,~ um,~ and things like that. However, there are also use cases where,~ um, you know, that ~that just becomes very complex. So ~I, ~I think that ~it's, sorry, it, it, ~it sort of become an anti-pattern to just use dates pretty much everywhere and it creates a lot of complexity. Noel: Yeah. Yeah. ~I, ~I feel that as well. ~Like, I, I, I think, again, like I'm, I'm cur I'm curious because I, I, ~I feel like ~the, ~the common thread here is like o often in ~these, ~these other alternatives, ~you go, ~you go through, you're talking about ~like, um, you know, uh, ~grouping related data and ~like, uh, ~putting things like in the query string. ~Um, ~like ~we get, ~we get into this mode where you're. Often ~if, ~if something's using use effect, like that seems to be the point where it's like, okay, maybe ~like, is there, ~is there something else we can do [00:04:00] here instead of use effect? ~Did, did you,~ do you notice that at all? Do you feel that it's the case? ~Like ~if there's a lot of effects happening, that's usually an indicator that something may be amiss in ~a, in like ~the design of a component. David: For sure. Some of the hardest to debug problems is what I call a cascading chain of use effects. I talk about state machines a lot, so I call this specific pattern a Rub Goldberg machine where ~I'm, ~I'm sure you're familiar, it's ~like ~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 a change in the first place. And so that's chain,~ uh,~ 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 dates and use effect Noel: Yeah, at least personally I've found that ~like ~if I'm at the point where I'm in use effect. And that effect is triggering any further state management. I'm usually like, okay, now I'm in like the danger zone.~ ~ ~Um, ~but I often don't know ~which kind of like~ where to go [00:05:00] from here. And I end up just ~kind of ~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 reaching for or is there, is it ~kind of ~like It depends on the situation a little bit more. David: It depends on the situation, but also there's a big thing that I feel a lot of React developers missed because ~as, ~as developers, our go-to is just, okay, which tool is right for this job? Okay, you state 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, ~you know, the, ~the state might not actually, I. 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 [00:06:00] this a good use case for use dates or use reducer 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. So basically. In any given state, ~like ~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. Noel: ~Yeah. Yeah. You also, you also touch, um,~ I, I wanna kind of circle back to ~uh, ~like query string and local store and those kinds of things. But on this problem specifically,~ you all, ~you ~kind of ~touch on,~ um,~ like discriminated unions, like kind of ways of actually encapsulating these. ~Um, ~I don't wanna overload our terms here, but these kind of like complex states of being that like a given component can be in that we're, we all like often end up ~kind of ~trying to mangle together and ~like ~suspend across several variables. ~Um, can you kind of, ~can you go over that a little bit briefly and ~like what are the kind of key or ~what are the [00:07:00] primitives there that like may be helpful to ~kind of capture, ~capture that complex state that's living across multiple variables in certain components? David: Yeah, so discriminated unions are great. It's probably one of my favorite,~ uh,~ type features or type script if you're using, ~you know, ~type script. ~Uh, ~with a discriminated union, you could essentially say that in objects. Is discriminated based on a single property, and for example, that property can be status. So ~I'll, ~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, ~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. ~We, uh, status.~ 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 ~sort of ~mixed [00:08:00] 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 dates. So that's why I think both grouping related states and using Discriminated unions are extremely useful. And so thi this, I would say, is the first step to thinking in terms of a state machine without actually having to use a state machine. Noel: ~Yeah. Yeah. Let's, ~let's ~kind of ~talk about this ~like. ~Kind of state machine concept. It feels to me that this, these kind of discriminated unions particularly,~ um, used~ when used as ~kind of ~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? ~Like ~that's how we think about the release is like this. ~You know, ~hook is, or this component is in like one of five modes, like we're loading, we're submitting, or ~you know, ~like it's in an invalid state or a valid state. Like, oh, like these different [00:09:00] modes. And I often see that. ~Um, do you think, ~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. 'cause I feel like this is where I always see this is, it's like ~the, ~the current kind of status of a given component is in this union, but for each one of these, the developer is tasked with ~kind of ~like determining that needs to happen and setting it up. ~Do, ~do you think ~that ~that's a common enough pattern that like it should maybe be abstracted a little bit? David: I think so, and recently there was a new React, API, where ~I, ~I tweeted about it maybe a few weeks ago, but it actually did have a, oh, ~it it, ~it had something to do with animation. ~And so, um, or at least I, I believe so. ~And it was actually using a string enum. ~Uh, ~you can't see it, but I'm putting quotes because,~ uh,~ JavaScript doesn't have native enums or anything like that, but it's basically using a string to specify the status,~ uh,~ which I think is really great. ~Um, ~and it does eliminate a lot of that,~ uh,~ that Boolean mess. Now there's other hooks too, such as use action states, which will reveal. [00:10:00] A, for example, an is pending variable. And so again,~ this,~ this might be going against what I say where it's like, Hey, try to use stringing noms instead of variables. But I think things like is loading, et cetera, 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 bullying 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 stringing noms and like these discriminated unions, you could actually prevent those from ever happening. ~So, uh, ~do I think it should be built into React? ~I, ~I think that's, react is on that path already. Which is good. ~Uh, ~and there's libraries too, like reacts query that also have ~like ~this,~ uh,~ status that they reveal. ~I mean, ~you could still use is loading as pending, et cetera, but they also reveal a status stringing them that you could use as well. Noel: ~Yeah. Yeah. ~I guess ~on, ~on that note of ~like ~the direction of React, ~do you think, I guess, ~do you think the React server components. Help solve this problem because [00:11:00] in your talk you ~kind of, ~you go over how ~like ~there's the kind of an intrinsic state layer added there, but ~like, it, ~it almost feels to me like this is just ~kind of like ~another layer, ~like that can be,~ that could be ~kind of going, ~going wrong or adding to this kind of like web of state and rendering and all this stuff. Do you think react server components make this simpler or more complex? David: When we look at how React developers typically fetch data with use effect and stuff, that alone contributes to a lot of complexity because they think, oh yeah, we could just shove it in the use effect. Have three or four use dates managing the data, whether it's loading, et cetera. And you could imagine just all that boiler plate, just how many lines of code that adds to a code base. 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,~ um,~ this data is loading. 'cause, ~you know, ~we have a suspense boundary, we could show a spinner or something. And,~ uh, you know, ~this data is loaded from that server component so we could actually show that data on that component. So I think [00:12:00] just for the simplicity alone of,~ um,~ of being able to load async states before a component is rendered to the front end,~ it's,~ it's extremely useful in that regard. And it does. Eliminates a lot of those,~ uh,~ state management problems that comes with async data. Noel: ~Do you think,~ 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, in two places or in the server and then having to be dealt with in the front end? ~I.~ David: So I, 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, et cetera. But,~ um,~ I'd like to say that like when you're doing things such as async data, that's like a one and done type of thing. But that's not always the case when it comes to dealing with async data. We might, for example, ~try, uh,~ try to subscribe to [00:13:00] something or get things over time, ~and it's like, ~and that's why we have to ~sort of ~invent solutions for things like I. A lot of people are building AI powered chat apps and so that, that has to stream data in. But even besides that, there's a whole host of other problems where we have to, ~you know, ~subscribe to something periodically or sync some local state with some external states. ~Um, ~and then, ~you know, ~that just gets really tricky. So server components definitely do not solve ~for that. ~For that major use case and very common use case of you need to load data and show it,~ it's,~ it's really great for that. Noel: ~Yeah. Yeah, I agree. I'm, I'm, ~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 like 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 ~like, ~those are maybe an apparent component that you're like trying to keep in state, ~like ~or in sync over time. David: That's where React Query is still king there Noel: ~Yeah,~ yeah. I agree. Yeah, ~I guess, um. ~I think, yeah, like that's probably ~as, ~as ~kind of ~good, a good, a segue as I [00:14:00] need to talk about libraries a little bit. ~Um, I, I, ~I do want to touch briefly ~bef uh, and this is, we're kind of, kind of in that mode.~ You mentioned,~ um,~ like query string logic a second ago and how devs aren't reaching for it quite as much anymore. Or it ~kind of ~gives one anxiety when you're on a page,~ like,~ I'm afraid to reload 'cause I don't know what's going to happen. ~I've, ~I've found this as well. ~Um, ~but to me that almost seems ~like, like a, ~like a different problem again. ~Like ~that could be. ~Um, ~it's can be local storage or query string or whatever it may be of like state that is ~kind of ~core to an app,~ not,~ not persisting for whatever reason. ~Um, ~do you think that this is like actually kind of part of the,~ this,~ this complex re-render 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 upon reload. David: Yeah,~ I,~ I think that, ~you know, using, um,~ using the URL for data 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's gone, or I lose my filters and settings and whatever. ~That's, ~that's a very [00:15:00] real fear, and that's why,~ um,~ remix ~sort of ~makes it a little easy ~to, uh,~ to use the query parameters. But there's also libraries like Nux and UQS,~ uh,~ which also makes that very easy. And I believe that,~ uh,~ Tant Stack Search and Tant Stack Router,~ um,~ 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, ~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, um, yeah,~ I,~ I think that more and more developers should use it. Noel: Yeah. ~This, ~this kind of brings me back,~ um,~ it's been a while since I've ~kind of explored,~ gone down this path, but it does make me ponder it a little bit wherein like I. Again, ~there was a, there was a, ~there was a time when ~everything, like when, you know, reduc, ~everyone was using Redux and everything was~ ~ ~kind of ~being pushed there. And then~ then there was like,~ people were like, well, what if we just ~like ~serialize the whole state and stick it in local storage and ~like, ~so it's always there. Then like whenever you render, you pull ~the whole that,~ that whole thing out. And I feel like ~that, like this, ~this was the problem that we were ~trying to, ~trying to solve. At that time, do you think that there's anything ~like,~ to that notion, ~is that, ~is that [00:16:00] like something that could be considered and have you seen any tools that kind of go this direction? David: So ~the, ~the problem with that, and like with. ~Early,~ early redux in general, is that it? It's trying to prescribe too much where it's like, no, just put all of your state in global state and, ~you know, ~obviously you could sync that with local storage or what have you. ~Um, ~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 share 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 size fits all solution and that, that's something that I wanna emphasize. So ~when, ~when you think about ~like, ~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 [00:17:00] 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 ~into one place. So that's just a reality. We have to accept and avoid complexity by just knowing the proper patterns to choose. Noel: Yeah. Yeah, agreed. Again, like ~back ~back to an example of ~like ~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. I. Without persistence. ~Do you think that there is some kind of, um, or maybe~ have you encountered any libraries or thought about this problem wherein like it's easier to store state ~kind of ~in the query string or in local storage or wherever it may be? ~So it's like not, I guess~ so ~it's, it's kind of always more of a, like a, a,~ that property of having it persist is a little bit more top of mind versus something that has to be kinda like consciously considered by the dev every time a new state is added. David: So Nux handles this problem nicely where ~it, I mean, ~it's not automatic. You're essentially replacing use state with used query states. But ~I, ~I would say having that [00:18:00] explicit is going to be a good thing anyway, because the problem with making it implicit is that I. 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~ sort of a, uh, a, ~hot stake or against the grain sort of way of thinking in the past where it's like,~ why,~ why write things verbose? Why write things explicitly when I could just have. The library do all of its magic for me behind the scenes. But nowadays,~ uh,~ with AI powered coding assistance, it does all that boilerplate for you and it is better to see those explicit things upfront. So, you know, replacing use state with use query 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. Noel: ~Yeah. Yeah, I think that that's, um. I think, yeah, I, I, I, I, ~I think like, like explicitness and devs, devs seem to be minding it less and less. ~Um, ~let's talk a little bit more about this kind of,~ uh,~ just [00:19:00] third party state libraries in general. I feel like we've ~kind of been, ~been skirting dancing around this a little bit. ~Um, so again, like I, I feel like this was, it was,~ this was almost easier before ~again, like when, ~when there were fewer options. I feel like there's a lot more kind of players in this space now. ~Um, is there like. When, ~when do you think devs should be ~kind of ~considering that, using a library at all versus to your prior point? Or just ~like, ~eh, just make it explicit, build it yourself. Like how do you ~kind of weigh that, ~weigh those two options? ~Like, ~like ~when, ~when do you recommend devs reach for a library? I. David: Yeah, so ~there's, ~there's a spectrum. Of course, you start with use state for local states and ~uh, ~component specific state, and then once your logic has more specific rules to how the state should be updated, that's where use reducer comes. ~Really, really, you know, it, it, ~it comes into play ~really, ~really well. And then if you need to share that state now, you might be considering, okay, let's put use reducer into,~ uh,~ context. So that it could be spread between multiple components, but then,~ uh,~ number one, you're ~sort of ~writing a lot of boilerplate and probably reinventing a few wheels. And secondly, you have performance issues too. And so this is what library solve and sure, there might be a lot of [00:20:00] options. In fact, I contribute to some of them. I have X State and a newer library called X State Store. ~Um, ~and of course there's many popular ones like Redux Done, jot, recoil, et cetera. ~Um, ~but I would say that these libraries really come in two flavors, or you could think of that 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 directly. There's no rules. It's like Joe t 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, ~you're providing an intent. You're like, I. Or in events. So the user submitted the form, the user changed this field, et cetera. And then based on that, you're not directly updating states. Instead, it's indirect, and the logic within the store says, okay, given this event, I know how to update the states according to my rules. So that's what I'm going to do. [00:21:00] 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,~ um,~ yeah, so ~I, ~I would say just choose the option that is, ~you know, ~most comfortable for your team. Something where everyone can agree, ~you know, ~how to use it properly and be most effective with it. Noel: Yeah. Yeah. ~I, ~I feel like there's ~kind of two,~ two ~things to, um, I dunno,~ data points that kind of weigh into that decision is like usability and like the shape of your app and also performance. ~Like, have you, ~have you found that there's like either of these kind of options, one that's more,~ um,~ like reducer, like where there's a function that's explicitly defined? By the store versus like directly mutating it where needed. ~Do you, do you find,~ have you found either of those are more performant or lead to performance issues? David: It really depends on how you use it. So with the store-based approaches, you have to use a selector. And ~the, ~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 [00:22:00] going to change every single time. So now you have to have a better way of saying,~ like,~ either memorizing that results based on,~ uh, the, ~the parameters for selecting it or for filtering it. ~Um, ~or using a comparator or something like that, like shallow equal, something like that. ~Um, ~so there's that consideration when using stores, but with atomic states, so a state based on signals or atoms, you ~sort of ~have that automatic, since they, they deal with much smaller pieces of data,~ uh,~ you, you ~sort of ~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 'cause you're not changing a large store. Instead you're changing individual pieces of data that you could individually,~ uh,~ subscribe to in a fine-grained way. ~Uh, ~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 ~if you have bigger,~ like if you're dealing with larger data in a [00:23:00] store, then. You can't really just shut that all into an atom because then you'll have the same problems, Noel: ~Yeah. Yeah. I've, I've off,~ I've found I've most often encountered this, where I have ~like. Components, like ~a list of components. And then each of those like cares about a specific slice of ~like ~an array, right? It's like, oh, like this is number whatever, seven or the one with this id, right? And like it needs to then prescribe it 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. ~Um, ~but I think that ~you, ~you put it nicely there and ~kind of that is the, ~that is the part of it that you thinking about how you actually,~ um,~ like filter and look at the data, I think is the thing that dictates probably which one of those two paths is gonna be kinda less painful for you,~ uh,~ to ~like~ use long term and then figure out how you wanna mutate it from there. ~Um, ~ ~yeah, I guess do, do you think. Are, are we often thinking about, I guess, so you, in,~ in the talk you kind of talk about how ~the, ~the events driven approach kinda has a lot of,~ uh,~ just intrinsic benefits back to your point of ~like ~being explicit and traceable. ~Um, like do you think that there, uh,~ do you think that devs are ~kind of going for that,~ going that route less often than they should be and reaching for something where they can do direct mutations and ~it's, ~it's causing problems? David: ~I, ~I think they do [00:24:00] go for it less often because the, ~you know, ~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 ~that is ~very, ~very important, even if you're just using it for council logging or seeing ~like, ~okay,~ what,~ what series of events led to the state being in this? ~You know, ~potentially inconsistent states so that I could start to debug and, ~you know, ~go based on that. ~I mean, you, ~you can't even trust things like,~ um, a, ~a call stack because things might be async, things might not happen exactly ~as,~ 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, on the next render cycle, et cetera. So you can't just. Go back in the trace and see [00:25:00] 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 events and have the logic change and understand that, okay, yeah, this same event will now do something different because my logic changed. But,~ uh, the, ~the intent is still there. I know exactly why this data changed. It's because this event was sent. Noel: ~Yeah. Yeah. Um, do, do you think that there's like. So part, part of this is like, ~I feel like we're ~kind of ~telling ~the, ~the same story in a couple different ways here in that ~like, you know, ~like use reducer is nice and like event-based mutation at a global, the global level ~is also, ~is also nice. ~Um, ~because ~you, ~you ~kind of ~get ~this, ~this traceability and you can ~do these more complex,~ make these more complex changes. ~But part of me is I think like, I think it's interesting that ~I feel like when we were in the old like class base react. ~This was kind of like that.~ That was ~kind of ~the thing you just did, like that was ~kind of~ what you always tended to reach for. Do you think that this ~is like, ~was less of a problem before and we've ~kind of painted, ~painted ourselves into a corner a little bit with ~like, you know, ~you state and that ~being ~being the hook that is the default, David: ~I, I, ~I think it was somewhat less of a problem because, man, I remember way back then,~ um,~ you used methods for all of Noel: right? Exactly. [00:26:00] Yeah. It was a function. Yeah. David: Yeah. Methods are essentially ~those, ~those events in a way, and again, I'm putting hand quotes because,~ um, you know, you, ~you could ~sort of ~conceptually think of them as the same sort of intense driven thing where you know,~ you,~ you say, I want to do this, and,~ uh,~ based on your centralized logic,~ you,~ you would either change the state or do something else, or maybe reject that. ~You know, ~just whatever. So yeah, it, it was less of a problem. And hooks unfortunately do make it a lot easier to just directly update the state. Noel: ~Yeah. Yeah. If you were, ~if you were like redesigning React Today or ~kind of were, ~were in those rooms ~when, ~when the hooks were being discussed, would you have advocated for something different or would there be any kind of. Subtle changes to ~how, ~how that state management kinda was, ~you know, ~prescribed. David: I don't know how much I would change. ~Like I, I mean, I, ~I really like, for example, the way that ~Pels does, or sorry, ~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. It's just a [00:27:00] really good use case for it, and you avoid a whole class of performance issues that way. ~Uh, ~but for things where ~you, ~you do want that indirect state management, you want that centralized logic. I would move closer to something like Spel doors, and I know that React is considering this. Idea of a store. ~Um, it's, ~it's really a huge missing piece in React that other frameworks do have,~ uh,~ either as a blessed third party library or something built in like Spel stores. ~Um. ~That's the one thing that I would ~strongly, ~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 state. You could wrap it and just going back to what we talked earlier,~ uh,~ 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, ~that's something that I would've [00:28:00] pushed for more. Noel: Yeah. ~I mean, ~I think, I feel like the React team had, ~you know, ~like ~they were, they were, ~they were thinking about this at the time, right? But ~I, ~I had, I have to assume that it was kinda like, eh,~ if,~ if devs needed, they, we have like external libraries, ~they can,~ they can reach for it. And I, yeah, ~I kind of, ~I ~kind of ~see the decision both ways, but part of me always felt that I. I like the reason, and ~I, ~I don't have any data here, just ~kind of, ~this was just ~a, ~a vibe. Was that like ~the, the, ~the idea was that less and less data would need to be ~kind of ~pushed up and shared in like ~this, ~this whole global. State object and ~like ~that was ~kind of ~an anti-pattern. That was ~what I, ~what I was alluding to with ~like, ~my very first question. When you and I first started talking, ~did, do you, I guess, ~do you think ~that ~that ~like was a, ~was a thing like ~I, I ~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 gonna 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 like, ~did you feel like there was ever that tension there? ~Did, did that, did that, was that kind of,~ or am I inventing ~this, ~this whole,~ uh,~ history in my head? David: No, no, you're, you're absolutely right. And it's ~sort of ~a pendulum swing. There is the idea of all states should be, ~you know, ~local and atomic and whatever, [00:29:00] and just ~like, uh, ~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. Single place for global store is not really realistic just because there's multiple sources of truth. Again, we talked about the URL, the database, and then,~ um,~ even different concerns within the app. So let's say you have a an e-commerce app. The carts 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. ~Like, you know, that's, ~that's just not reality and you're gonna make things more complex that way. ~So, um, ~in reality ~it, it, ~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, ~from everywhere. Noel: Yeah. Yeah, ~I think, ~I think that's [00:30:00] tricky. ~Like, I guess. You know, ~as a dev,~ I,~ I agree that ~it does, ~it does always feel like a balancing act. I feel like ~most, ~most people practically ~like, kind of, kind of ~feel that as well. ~Um, is, is there, I guess when, ~when you are looking at these kinds of things,~ um, you know, and like work,~ working on the tools that you work on,~ how,~ how are you ~kind of, um, ~balancing ~that, like the, ~the pendulum of, ~you know, ~like modern opinion on maybe how much should be global versus local? Compared to ~like ~what you think is actually the correct kind of,~ uh,~ architecture to generally prescribe to users of ~like ~the APIs of the tools that you're working on? David: 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? ~Like ~if I have ~a, you know, like ~a to-do app or something like that, I. Where do all of these to-dos belong? How are they grouped? What are the properties of each, et cetera. And then there's ~the, um, you know, ~the sequence diagram that I would think up of ~like, ~okay, what are the [00:31:00] external parts of my application that need to communicate with each other? So I might have ~like a, ~a, ~you know, ~to-do service or in authentication service. And thinking about what are gonna be my fetch calls, et cetera, for that. And then of course there's the state machine, which just tells me I, 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 ~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 states 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 [00:32:00] shared concerns can be in use reducer or third party 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 use query or even the URL as states. Noel: ~Gotcha. Gotcha. Do you, ~do you think that this ~kind of, this, uh, I don't know, ~demystification or trying to make it sound less scary of like the concept of state machines? Is that part of your ~kind of, uh,~ value prop with stately? David: ~It, ~it is because ~I, ~I like to, ~you know, ~present stately as a tool for thinking, not a tool for, oh, you should be doing everything with state machines. ~Like, ~it's just. It allows developers to, 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, you know, ~these things. When some part of my app is in this state, only these things can possibly [00:33:00] happen. And this is how the state is updated when those things happen. So ~it, ~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 wanna avoid ahead of time. Noel: ~Nice. Cool, cool. Um, I guess, yeah, I, I wanna move on to our, uh, kind of lightning round questions here. These will be just like quick, quick one-offs, one or two sentence answers. Um, before we do that, ~I want to ask one more question on if there's anything you'd like to see,~ uh,~ in kind of state management,~ um,~ react 20. ~Like is there, ~is there anything fundamental you'd like to see as ~kind of ~like a next step or generally the path forward just for this kind of state with React conversation? David: Yes, I wanna see ~first, ~first class support for stores. React has usy external store, but then they have ~sort of ~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 Noel: ~Mm-hmm.~ Cool, cool. ~Um, ~alright, so I'm gonna get ~into our, ~into our lightning round questions proper here. ~Um, ~server components, overhyped or the future I. David: 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 [00:34:00] technology. Noel: Ah, nice. Yeah. Agreed. Agreed. ~Uh, ~do you trust AI generated React code? David: ~Uh, for, ~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. Noel: ~Yeah. Yeah, for sure. Um, ~is there one react feature you wish more devs understood? I. David: Yes. I would say use producer. It's one of those ones where it's ~like, ~let's shy away from it. Let's not use it. But it's very useful when it's necessary. Noel: ~Yeah, agreed. Agreed. Again,~ I feel like it's one of those things,~ kind, kind of like just getting state, uh, or~ like actually just having derived state in the render, like user's, ~it can, ~it can save ~so much, ~so much pain, lot, or again, at least delete a lot of code. Like we just don't need all this logic here. ~We can just, ~we can just do the thing. ~Um, ~okay. Cool. ~Uh, ~how do you feel about context for state sharing? ~Uh, ~is it a necessary evil or a solid tool that should be used? David: ~It is a,~ it's a solid tool used badly. ~I mean, ~it's great for dependency injection like themes, off 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 [00:35:00] for stores and context is that unfortunate. Necessary evil for dealing with global stores right now. Hopefully that changes in the future. Noel: Perfect. Cool. I, that's all I got for,~ uh,~ 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. David: Yeah. ~So, uh, if, ~if you don't know, ~I am, ~I am the creator of X State, which is a state, ~you know, ~state machine,~ uh,~ state management library. But I also recently created X Date store, which is very close to Zest Stand, or you could think of it like a better use reducer,~ uh,~ but also Joe Tai, because it does have those atomic based state updates if you want to use that. And so this is something where ~I, ~I really think that if the developers want something simpler than X date, they should check out X date store. Noel: ~Perfect. Yeah. Cool. Yeah, I'm, I'm a, I'm a big, uh,~ I'm a big,~ uh,~ stand user, so maybe I'll have to explore a little bit and check out some other tools because ~I've got, uh,~ I've got a couple projects I've been ~like. ~In this mode of ~like, ~this is all gonna be global state. So ~I need, ~I need to check some new stuff out. ~Um, ~but anyway, this has been a pleasure. Thank you for coming online, letting me,~ uh,~ pick your brain a little bit, David. David: Thank you so much for having me. Noel: ~course, ~of course. Take it easy.