Please be advised that this video contains language that can be considered explicit.
Joel and Jared chat about the essential questions around State management; they concluded that there is no silver bullet in dealing with State Management. The conversation also included an overview of how URL-driven Applications are used to maximize SEO performance (they do this by keeping State the URL). Jared also gave a walkthrough of Formkit and Recoil. He expanded on how Recoil solves performance when you need to update State in a deeply nested tree.
The biggest question that you need to answer: Where is this State going to live?
You should never have State in two places at any time. Do not duplicate State.
You need to have a single source of truth, and it needs to live in one place.
The best way to level up your State game is to learn how to normalize.
The process of normalization is heavily used in every software design because normalizing data has a significant impact on reducing data redundancy.
Normalizing data with unlock performance gains. You need to have a single source of truth for each atomic unit of State. And you only want to make a change in one place.
Immer - write mutual code.
Using immutable data structures provides many benefits, including making your code easier to reason about and less prone to bugs.
Immer - It's useful when making an update at scale using structural sharing. It's super fast, perfect for large nested lists.
Jared Palmer: [0:00] All right, so it's a state management, right? That's what we're talking about?
Interviewer: [0:04] Yeah, please do some background. I've been asking people as they roll through Egghead, as they get subscriptions, I was like, "So, what do you struggle with? What are you dealing with right now?" State management came up a bunch. I was like, "Well, I'll go down, and I'll do the full-blown research project and dive into some...
Jared: [0:27] reaction, huh?
Interviewer: [0:28] Yeah. Even beyond that, it's more like we...
Jared: [0:33] Like we asked?
Interviewer: [0:34] Yeah. That process is [inaudible] . It gets into jobs to be done and stuff is what we're exploring which is all related to Sail Safari and Ethnography and figuring out why are you signing up now, what's the point, what's the outcome you hope to achieve. Then, at the same time, we're also developing curriculum and thinking about what is the big picture.
[1:01] We have traditionally released at the unit level. We're in a GED courses. It's a unit. It's not talking about React or Web development, or React like state management, and state management and React and the encompassing themes, which are often presented as paths. I hate paths, like I said, like learning paths, I don't like them in general because I don't think anybody learns in a very linear way.
[1:31] I think we're all just in time. What do we need now, what are we trying to accomplish kind of approach. That's where the state management stuff comes in. I started talking to people and doing...I was like, "Well, I'm digging in." As it happens, people chat with me about it, so I thought that was more interesting.
[1:49] One of the things I'm interested in is what you have done in practice. You're running a business. You've created Formic and what does that look like from a state management perspective. It'd be cool at the code level. Then, I have a few questions we'd go through and just get your ideas on state management in general.
Jared: [2:14] That sounds awesome. Largely, the reason why my guess is why state management comes up as people's pain point is because it's the app. That's the crux of it. That's where the shit happens.
[2:25] If you understand state management and React, you understand React at the most deepest levels. It's an art form. You can learn all the APIs and shit, but when it comes down to actually being productive, managing state is all you're doing, especially nowadays. I feel like that. When people say, "Oh, state management," it makes sense that they're, "That's the hardest part," because that's the fucking doing.
[2:56] To me, I think about it in these weird systems. Almost like, I guess, spoken language level structure. In the sense that I have heuristics that are probably not too dissimilar to the way a grammar works in natural language processing.
[3:15] In my brain, I have this intuitive sense of, "Oh, no, I need to normalize that," or that's going to be a...I still have these heuristics that I think we discussed briefly on Twitter that I built up over the years of hammering away a shit. Happy to walk you through how to form a cloud, like store state. How we want to store state in the future, and where it breaks down to, and then where it's really, really good.
[3:41] Then the other part we could also do is how I only focus on state management, in some sense, by generating code for shit that is competitive, so that I don't need to do anything other than manage state, if that makes sense. I don't know if that does...Basically, we generate all of our fetches. We don't have to write any fetch code.
Interviewer: [4:05] It's like you're using robots for all intents and purposes. Your automation to handle a bunch of the work that lets you think at a higher level.
Interviewer: [4:16] You're not exercising your brain on these lower level problems, where you would spend a bunch of time, probably, and then you're able to think about stuff, and compare to a different level.
Jared: [4:26] Even nicer, as you change the name of a key and that with, thanks to five and a thousand lines of TypeScript in the codebase or the things that are not performing sometimes. Thousands and thousands lines of all TypeScript from day one, and calling backend, we generate something new, you could be drunk and fix the errors.
[4:41] These are just one less thing you need to think about. I will say that I became a lot better at state management when I start using TypeScript. [inaudible] program where I start using TypeScript. I got better at state management, because, you get to see it in TypeScript. You see the way the interfaces, the shit patterns in the types, and the API services, and the footprints.
[5:08] For me, I start recognizing patterns. I'm like a systems person. I start seeing when these patterns work well, when they suck, what hurts, and when it's annoying when I'm typing the same thing over again and when I'm not. I don't know.
Jared: [5:54] The ability to jump around the repo and preview what's beneath the interface in TypeScript and then also being able to when you do work with team members. Everybody knows or can look up very easily what all of the state in replication is and all of the actual data in your application is, and you all agree on the names for shit.
[6:17] You have conventions around the names for shit because you probably named some early in TypeScript. You can also see it visually in...Again, as you mentioned new graph, I find that helps with communication immensely because everybody knows what a user is at a much more deeper level.
[6:45] It may not be exactly...That's not going to be frontend state. You don't really know. You go to our user type, you go API Modo user, that's all the shit user and that's generated from the API. It's end of the discussion. So, that's extremely helpful.
[6:58] It's not perfect all the time. I'll be happy to show that to you, but anyway, I find that combination of very strict TypeScript and a small set of rules to reduce cognitive load is unbelievably powerful. Yeah, I guess we can jump into it.
Interviewer: [7:20] Quickly, if you were to think about maybe the big ideas or the questions like the essential questions that people should start considering before they even jump in the code about...When you start planning that, what are you going to sit down? What should you be thinking about when you're narrowing down states managements for an application?
Jared: [7:47] The biggest thing is where state is going to live. That's thing one. By the way, the answers are not so obvious.
Interviewer: [7:54] Or the obvious answers are not necessarily the best answers.
[8:22] The first thing you have to understand is you should never have state in two places in React. I have never successfully kept state in two places except once. Maybe one time I did it, but it was very hacky. I hid the shit that was duplicated so that the user couldn't even see it.
[8:40] That's only because it's a third product. By and large, do not duplicate state. What that means is if you got a control versus uncontrolled component, which we'll get to in a second, you need to have a single source of truth. I need a single source of truth and then where is this going to live?
[8:56] It can live in a few places. It can live in memory. What I mean by that, it can be my memory, I mean in your code, inside of...I like to think of these as physical locations in my head. In your code.
Interviewer: [9:09] If you hit refresh, it disappears.
Jared: [9:11] Right. That kind of shit. There's local storage, there's session storage -- you can keep state there - and the URL bar, your actual...The URL itself cannot hold storage in old state and actually technically, the browser history can hold state, too.
Interviewer: [9:29] I've seen that described as router state which is a little...
Jared: [9:33] I don't fuck with that, but...
Interviewer: [9:35] I mean in people think like React router when you say that.
Jared: [9:38] No, no, it's more like the Modo. If you want to do a Facebook or Twitter Modo, where like if you're in Facebook or Twitter or Instagram on Web and you click on a Tweet, it used to pop up a Modo if you click on it. Then you hit X and it's gone.
[9:51] If you were to refresh the page, it would render that one tweet or photo. Server-render it and that path deterministic...That's path state, that's the router path you got to get to that entity. It would update the URL, but it would render the same component in two places.
[10:09] One would have a route that would render that photo thing. If you click on it, it will render that same component but in a Modo, but update the URL accordingly. Again, that's actually a place, the [inaudible] , you're duplicating component but the state always lives in one place.
[10:27] Figuring out where states is going to go is important and knowing ahead of time is not essential, but it is useful. We can always pivot around things, but definitely you've never done it before. I remember the first time I built a search interface. What I mean by search interface, I mean you search on Amazon. You've got this big side bar filters.
Interviewer: [10:50] We get that with [inaudible] , right? It's like a typical search with filters and facets and all that.
Jared: [10:58] Exactly. Facets. There are a couple of ways to do it. There's couple of best practices. What's annoying is different in desktop and mobile, but let's just fill this on desktop for a second. On desktop, when you make a change in the sidebar, you want to see it in URL.
[11:15] If you're a public site, you want these pages to SEO very well. You can do fancy shit with URLs by the way to make that way better.
Interviewer: [11:29] I'm taking notes because ours is garbage.
Jared: [11:31] We can talk about this another time, but basically, you should be writing and using...Its entire subject is called natural language generation. Natural language generation is the science of taking random data and turning it into a sentence.
[11:51] This is actually a pretty good application for AI, but Pinterest does this. They take their perceived...what they think is an image using image recognition and they construct the title tag for the page and furnish a description as well.
[12:13] You could also take a URL and you could store state in the URL, and it's really cool. You can actually store state in English if you've never thought about this. Here's an example, Nomad List does this really well. You go to Nomad List, you click some of those filters. It becomes countries in Europe with more than 2,000 GBP per capita, whatever the filter is.
Interviewer: [12:41] Is this like advanced search on Twitter? When you do advanced search interfaces where they'll do from, colon, at, name...
Jared: [12:49] No, no, no. If you go to Nomad List, you just read it...
Interviewer: [12:54] You can share your screen.
Jared: [12:55] Sure, I'll show my screen. Check this out. Zoom. Share screen. Let's go to Nomad List here. They're Nomad List. This looks like a little bit like they're having a tough time today. Guess we got this at the wrong time. That's interesting.
Interviewer: [13:20] What do they call that? #HogOps?
Jared: [13:23] Yeah. Oh man. Let's see, there's supposed to be all these filters and stuff. Maybe they're having a good time on mobile. No, they're not. This is the best version of this. Anyways, maybe this will be better.
[13:38] Looks like they have a CSS issue or maybe I have a CSS issue. What's my console say? Loading what? Not good. OK, that's frustrating.
[13:53] I can use the site that I'm working for my sister. It's actually not in React. It's called Parent List. It's a list of...There's WordPress site and it doesn't do this, but it should do this. We can use it as an example.
[14:07] These are resources. These are kid stuff for kids to do. This is a classic facet interface. As I click these facets like I want to do, I don't know, first grade math. You see this is the CRL right here. It says parentlist.org/resources.fwcategory=math and after grade level is first grade.
[14:29] That's a classic search query type of thing. That's good, but will be better would be parents.org/firstgrademathresources.
Interviewer: [14:45] Yeah. Literally URL...
Jared: [14:49] That's [inaudible] remember for it. Natural language generation and see this free. Better would be parents.org/freefirstgrademathresources. You can create a sentence with [inaudible] sentence.
Interviewer: [14:57] We do this like if you search for free egghead in your browser which is something people search for that and then you get...You get that first search for lessons. The title is horrible but the first result is community/resources which is all of our free stuff. Then you said doing this, that's great. You can see it's not updating anything like the rest of it breaks.
Jared: [15:32] This, what you're going to do is you want to take this and it'd be like...You can have it two ways and the way Amazon does this is super interesting from SEO perspective. You can get into how this work or basically this could be egghead.io/graphql.
[15:52] If you also had then it can be GraphQL lesson and it can be GraphQL lessons by Alex Banks as a sentence. You could also have that, this query as well. What we should do for this query is set the canonical URL to the primitive, want the primitive, whatever the core facet is. This is how Amazon works.
[16:21] It will show you is this. This is like SEO hacks, all has SEO hacks. Again, this is all state URL. Let's search for...I guess Nike's not there. What should we search for? Let's search for golf clubs. TaylorMade.
[16:43] We see here in amazon.com/s and the query is Taylor plus Made and that's TaylorMade for search query. That's cool. Now, let's go to TaylorMade Amazon. Let's see if we can find the brand. TaylorMade golf company, that will probably...
Interviewer: [17:09] Drivers TaylorMade, golf clubs.
Jared: [17:11] This is a store. I don't want to get a store. I want TaylorMade. That's the core one...Let's do, yeah, drivers TaylorMade, golf clubs. This is some search thing.
[17:25] If you look at the URL here in the canonical URL on Amazon, canonical...This one doesn't...If we do a search, it'll be like...I forgot this thing. Basically what they do is they keep the first...This is a wild card right here.
[17:49] See this? This is a wildcard. They can put whatever the fuck they want here. This is the query, but Google will read this as a unique URL.
[17:58] What they can do is, if you know, and this is some random ID, but you want to assign that an attribute, that search authority to this route that's a more English-language-readable thing that someone would likely search for, Google gives prominence to shorter URLs that are closer to English.
[18:21] You can trick it into thinking that you have a page called like TailorMade or Fu and you can set your economic URL back to that if you know what you're doing. Back to Egghead, this could be like you could have two pages, one that should be like GraphQL as the route and that should be your wildcard, and then add all the search query stuff onto it.
[19:05] That's fine. You basically have to ask yourself, "Is this worth doing?" It might be. Another good example of this is houzz.com.
Interviewer: [19:14] How do you make that decision? This is a design question almost. Not a graphic design but a system design.
Jared: [19:22] It's an SEO question. It's really an SEO question and also it's a shareability perspective. When you're building a BI dashboard and you've got a super-nested...
[19:33] Let's say you've got a company and a company has people in it, and the people have, I don't know, notes about people, it would be a really good idea to make every part of what I just said have a unique URL in the app so that you could send to your co-worker, or at least bookmark maybe, send your co-worker this note about that user at that company. That would make a lot of sense.
[20:02] If you don't have URLs, everything is the same thing, the application state effectively resets every time you go to it, so URLs are a place to basically share application state. Probably some smarter person can more eloquently describe it, but that's basically what a URL is. You're able to persist application state between two different computers, basically. That's where it's very useful.
[20:26] It's also useful for SEO. The determination of whether or not you should put it in the URL is, do you need to be able to share it with someone else? That's what it boils down to, for me. This is important with tabs, so you see tab interfaces a lot.
[20:40] Sometimes tabs are like, "Should this be tabs or should they be links?" It can look like tabs from a design perspective, but they can be links and you can use that URL to determine which tab you're on. That again comes down to, do I want to be able to share this specific tab with another person?
Interviewer: [21:03] URL is uniform resource locator which...
Jared: [21:08] That would be the definition of a URL.
Interviewer: [21:10] Yeah, and it's so you can find it again. That's the idea. Not only, "You can find it," but now, "I can share." We're effectively sharing state.
Jared: [21:20] You're sharing state is exactly it. That's what URLs are for and you can put up a ton of stuff. There's actually a limit to how long they can be.
Interviewer: [21:30] They've grown over the years. It used to be sadly short and you'd run into it and you'd have a horrible day of debugging and figuring out how to remove the client's name.
Jared: [21:38] You can use shorteners, too, so that's also fun. In your database you can have references where you can keep a shortened version of it and that expands into something else. That's where URLs come in. They're very useful.
[21:48] URL-driven applications are actually not crazy hard to build. The way I like to do that is to abstract away the reading and writing of URLs outside of your components, basically. You build two functions, usually. I like to build two or three functions and that's going to be like parse URL, URL to state, and state to URL. Sometimes it's just like state to path, whatever you want to call it, but you need to go to and from.
[22:21] That needs to be as far away from your components as possible. One of them is going to take the URL as itself, like just the whole thing at any time. Like, window.location.href. That's going to slap that thing into state.
[22:35] Maybe you'll take the user and the current URL, but it's just going to turn that into meaningful information. Then, your application is going to take that and it's going to render different React stuff based off that state. I don't mean like React state, I just mean like an actual object that it turns it into, so it's like URL to some sort of data, because it's not actually React state.
Interviewer: [22:57] Is that what React Router is doing for us?
Jared: [23:01] Yes, it's running match on the path you give it and when it matches the path it renders what its children is and then it's manipulating history in the background. It's running match, you declare somehow, some way underneath this React component, "Render this when the URL matches this."
Interviewer: [23:24] I would say, "It stops at the query params, though." Like it isn't concerned at all with, generally speaking.
Jared: [23:31] No, I don't think it does. That gets annoying, sometimes you wish it was. Now with React Router-4 you can actually build a thing that will actually help you with that. You can wrap it to do the query stuff, too.
[23:48] Similarly, though, you want to build something that lets you construct links using this grammar. What's nice about it is if you've abstracted these things away, reading from URL into data and writing a URL from data, now you can change the structure of either one and not have to change your React components past a point.
[24:03] If you want to add your natural language generation to the URL, you just need to change the thing that's interpreting and then the thing that's writing, but you don't necessarily need to change the data structure as long as you can, again, always go back and forth. It's a little bit harder than what I just described, but fundamentally, it's abstracted away now.
[24:25] The other nice thing about something like that is if you do change URL structure, you need to probably change it throughout your entire application, so having that nicely abstracted to and from URL is a very useful tool. You're going to make that mistake exactly one time and never do it again.
[24:43] It's a very bad bug to change if you need to change it or a very hard change to make if you didn't do that from the start. Anyway, I was illustrating with Houzz real quick. They have, you see this, "Houzz, products, furniture."
[24:57] This is furniture, "All furniture." Then you're going to keep going, "Sofas and sectionals." These are not query strings, these are hard URLs. You see they make it natural-language-like. See that's like, "Width 80 to 150." I don't even know, are they doing that? Yeah, "Width 80 to 150."
[25:22] Again, you're going to do a full-page refresh but this will server render this specific page first. You want to make it so that this would render this information and then again, it's a hybrid application pick-up from there. You don't have to make it like a classic NVC server-only, but you totally can.
[25:39] This is state. They're going to extract this. They're going to have some function that takes "Sofas and sectionals," and they're going to look for this "and." Where's "Sofas and sectionals"?
[25:48] If I had more of these, maybe "Sofas and sectionals," is one, maybe "Futons and sectionals," is one. This seems like it's the product, this is the product name, or they'd even have a "Query," one, maybe, even. This would be red. They tell you, "Width 80 to 150, futons and accessories."
[26:13] An interface that I built once, which was for a client, I don't know if it's still up. What have they done to this website? Oh, my God. Oh, my goodness. This is search results for "Kitchen, members." We built this. This is all Algolia-powered so they have like badges and stuff.
[26:32] Let's go to "Photos." Let's just go back to all the photos in the section. They have where members can upload photos and it's like an interest clone and you can view the photos. They're big. They like them big. It's cool.
[26:48] What I want to show you is the search interface. We've got "Room, Kitchen or Bath," then these different filters. All this state is held in the URL. Every time I'm updating this I'm just changing the URL. Then I'm parsing that information, this gobbledygook, into an Algolia query, so that's what our state is living in, but I'm not keeping state in a React state right here, I'm just keeping it in the URL.
[27:20] If you're not keeping it in the URL, the other place to keep it is in memory or in local storage. We'll just talk about local storage real quick or session storage.
Interviewer: [27:28] When you say you're not keeping state in two places, you're not going to move that into your component state also? You're not going to set state and drop that in there?
Jared: [27:37] No. Think about, "When you have state controlled in the URL, everything downstream of that is basically a controlled component." It's not setting its own state. It's a presentational component at that point.
Interviewer: [27:53] I parse that and flow it on down, basically, like another component tree?
Jared: [27:57] They're dumb components at that point. The only thing that could take some logic, but usually it's hard-coded or programmatic, is, again, the thing that's going to create links, because that is basically the way you set state is by generating a link, if you think about it.
[28:12] That's the way I think about it. Like when I showed you that other thing before, it was set to "Room," to "Bath," the way I'm setting state to "Bath," is by setting the URL to have that extra query of like, "Room equals bath." That is setting state in that sense, and the rest of everything works the same way.
[28:32] If I want to remove that I need to parse and then remove it from the URL, if I want to toggle that off. That gets a little weird. Then the other thing you should do is you should sort it every single time so that the same set of query parameters always show up in the same order. That's the other hack. Again, there are all these wrinkles that you could keep going, but yeah, those are useful ones.
Interviewer: [28:57] That's interesting to me because you're not only sharing state with your co-workers or loved ones, or friends, you're sharing state with Google.
Jared: [29:03] Yes, you are, very much so.
Interviewer: [29:08] It's browser state and more importantly for a lot of businesses, including my own, you're sharing, it's Google state and how Google deals with and interacts with your app, which is pretty important.
Jared: [29:21] Absolutely, so it is important to get that right. Even if you're not SEO-focused, you'd still want to do this if you were building a business intelligence interface or like a membership management thing, or any sort of thing with advanced search query filters, you want to be able to bookmark. You don't need to build "Save queries" in your app if you have these URLs.
Interviewer: [29:48] That's the way Command B works, right?
Jared: [29:48] Right, usually you bookmark it. If you've got this crazy complex filter, but it's all stored in state, or maybe make a bookmark of it, even better if you need to do something dynamic like, "Last couple of months," you can just do that and have that programmatic.
[30:08] If you've got state in the URL everything beneath that that you're going to read from that, not everything but, is going to try to derive that in a completely controlled way. Your Egghead filter is what I would call an "uncontrolled search interface." It's controlled in memory, but it's not writing it out. Shit gets weird too, though...
Interviewer: [30:33] It's a lazy bullshit interface," is how I describe it.
Jared: [30:37] No. Things can get weird too though because sometimes you've got state that lives in search but not...
Interviewer: [30:40] It did get weird.
Jared: [30:42] It lives in search but doesn't live in the URL. That's where the shit gets hard. Sometimes you need to have this interim state. Then you need to write the URL, but it's not every time. It's still a little tricky.
[30:54] Yeah, you could [inaudible] SEO by doing that. You could give people their auto URLs. You could keep a map in a database of a column synthetic. In WordPress, they call them rewrites. You could have like egghead.io instructor Jared Palmer-React.
Interviewer: [31:17] We wish.
Jared: [31:19] Right, but you have my approval. That could automatically set up a search query in the search interface of Jared React. It doesn't need to be a query string. That's my point.
Interviewer: [31:34] That's a really interesting...Almost write that down. I'm recording, so I want to come back. There's some literal work coming out of this for us.
Jared: [31:43] There's an SEO work that needs to be done for Egghead.
[31:58] If you SEO that, you're able to share that state, Google picks it up. Now you're not only sharing it with Google, but then you're sharing it with people that are searching and trying to find something specifically.
[32:06] You create this literate interface that Google finds, shows it as a result because they love showing people useful things, gets people to where they want to go. Then it also lands on the page that we want them to. We have some control over it.
[32:18] We can slow them through, show them the content that they want so they watch the stuff, and convert, and buy their shit. We can pay rent, and eat, and do all the stuff that we like to do. At the end of the day, it's a state management exercise.
Jared: [32:32] I think so. The last part of state that I would think of is application state. That's like art about that. The one thing that I would say to power up your state game, if there's one thing that changed the way I even thought about it -- and I can remember the difference in my code before and after -- was when I learned how to normalize things.
Interviewer: [32:54] That's a database terminology, normalizing. You denormalize. You break everything apart and do tiny little chunks. Normalization is bringing it all together. How would you describe it? That's a very horrible definition.
Jared: [33:11] Either you're right, or I have it backwards in my head. It doesn't make a difference. The point is that you need to have a single source of truth for each atomic unit of state. You only ever want to make updates in one place.
[33:22] Let's give an example. You and your database have a list of organizations, users, and tags. Tags can exist on both users and organizations. Users belong to organizations.
[33:34] Now, you have an interface where you're editing the name of the tag. In your data set, tag lives in four places or maybe a hundred places depending on the object of tag. Maybe it's -- I don't know -- cool or VIP. That could be littered across this entire JSON object, everywhere.
[33:58] What normalization does, assuming you can do it, will flip things on its head. Usually, the classic example is instead of keeping things in arrays of nested objects, keep things in objects that are key by some sort of unique identifier, usually an ID. Then their value is the object itself. Then you'd keep a list of all of the identifiers for a given entity or a filter on that entity.
[34:35] When you end up making a update, you only need to do one lookup of that using the lookup, literally whatever your entity object is, whatever your identifier is. You can just say entityID.title equals, boom, and you're done. That's the title. That will change the title in the tag no matter where it is in the entire tree.
[35:04] Again, you have to reconstruct the tree as if it's just references to do this ID. Then you use that ID to do a lookup. Basically what this does is it takes your nested list of stuff, turns into a database. Start thinking about your local state as a database when you're dealing with nested objects.
[35:22] When you do this, it's a little bit weird and awkward. There's a great library that Dan Abramov wrote and Paul Armstrong from Twitter [inaudible] called Normalizr that will explain what this problem is in depth.
[35:31] You just start normalizing state. You unlock a whole host of one performance skins. Two, it will make your life a lot easier because you don't have to update things in seven places.
Interviewer: [35:48] Things like Falcor and GraphQL seem to speak to this where you're doing ID references. You're referring an ID. Then that's a lookup table. You go, and you're able to pull that in. You don't have this littered mess of little fragments.
Jared: [36:06] Yeah. Apollo works by having, assuming that you have ability to uniquely identify all entities in your system. If you're using Rails app, you've got to create opaque identifiers somehow that are unique if you're using ID 12345 across multiple tables.
[36:25] If you don't do that, you have to manage it, yourself, in Apollo. I don't know. I haven't used Apollo in a while. It's not ideal when you don't have globally unique IDs.
Interviewer: [36:35] We do things like manage the type with the ID.
Jared: [36:38] Sure. That works too.
Interviewer: [36:41] You're getting a unique identifier. It's kind of crappy. It's not like doing a proper [inaudible] , but you're still getting that unique entity.
Jared: [36:48] It works. Apollo is doing all this normalization, what I just described, where it turns your state into a database for you. If you have done complicated Redux or useReducer stuff nowadays, you're going to need to run into that pretty quickly. That's why we select Formik, the Formik cloud builder, how it works.
[37:07] We have groups of fields in [inaudible] that are pages. It's quite difficult because each question can belong to a page. In pages, each question could also belong to a group. Each question could have children itself, like a radio question. It's like five or six levels deep.
[37:32] The way we model it is more like a layer list, like the way you build a tree menu or something like that where things have children and ancestors. You keep the list of children and then the data separate.
[37:48] Once you get familiar with the three or four different normalization patterns that exist in the world, things get easier. There's some cool ones too that are even more radical. There's a thing called a trie, T-R-I-E, that Twitter uses for search caching and stuff. It's pretty fucking wild. I can't tell you exactly off the top of my head what it is, but it basically caches the next most likely character.
[38:16] Trie deconstructs the phrase and lookup. If you're searching for Jared, the first result for Jared in that Twitter's Redux store will be users.j.a.r.e.d.
Interviewer: [38:40] This is some cute computer sciencey.
Jared: [38:43] Yeah. Apparently, that's slightly faster for heavy queries and stuff like that. You don't need to get there. You'll know when you need it. The big thing is understand how to normalize a list. That will get you pretty far. We're always [inaudible] that nested objects. The newest thing I've added to my state management foo is Immer.
Interviewer: [39:08] OK. That's going quite a bit, actually. What is that like? What is Immer doing for you that you weren't getting before? Why did you add that?
Jared: [39:16] Immer, I was first very much against. I was like, "I don't need Immer if I could stay immutable." Immer is a tool that allows you to write mutable code, and then it executes it immutably.
[40:07] With Immer though, you pass a function to set state. It's called produce. You pass a call back to this function called produce, and you get a draft. Then you can mutate that draft. Immer automatically can make an immutable update so that set state and React are happy.
Interviewer: [40:32] It's using all sorts of wacky...
Jared: [40:33] Proxies.
Interviewer: [40:33] proxies under the hood which are...
Jared: [40:37] Yeah. It's important to understand how...Actually, this bit me in the ass sometimes. You need to be a little careful with proxies, because they don't exist until they do. If you're trying to do normalization and denormalization, and you're trying to go to and from Immer, or mixing and matching immutable updates and mutable updates with Immer, it's just messy.
[41:00] Definitely read the docs. Try a couple of times. Why is it useful? It makes doing an update of thing...You have a list, right? You don't need to normalize it because it's not...
[41:15] You don't have multiple entities, for example. You've got a list of stuff. You've just got a list of users, for example. You're about to send out an invite to this list of users, but you want to change their email addresses easily. You want first-name email address.
[41:32] Instead of having to do all these array manipulation things or installing these old immutability helpers, like a helper tool or something like that, or creating multiple layers of components, you can use Immer. You can be like at array element index of three.title = Jared, and you're done. You don't need to do...It will fix the rest of it.
[41:58] Then what it does is structural sharing. It will smartly and intelligently make the correct, most minimalist copies of the old version of it, and make the one change it has to, and then return it. It's super fast.
Interviewer: [42:10] You used to have to deal with a burly library, like immutable.js that was not very fast and would bring a lot of code in and that kind of stuff.
Jared: [42:20] Immer lets you [inaudible] ideas. You can have local...This is like smashing array. Local mutation is fine. Global APIs that expose mutation is a bad idea. You can use mutation inside a function. That's going to be scoped and encapsulated but don't expose public API to your whole app.
[42:40] That's a mutable thing. That's [inaudible] , like you said before. Yeah, you can take local mutation in React. It's fine. It's just global mutation is not a great idea. This lets you to get some of the best of both worlds.
[42:53] There's a small performance penalty, by the way, with Immer, but it's very much worth it on super nested large lists sometimes and can save oodles of headaches around spreads, like spread death like, "I got to spread this. I got to spread this. I got to spread this."
Interviewer: [43:10] I get a kick out of spreads just because it's fun to think about, but it's a puzzle you don't have to solve while you're trying to code. It's like a logic puzzle. You have to think about it. Frankly, it's not great. Have you seen this? I'll share my screen.
Jared: [43:30] Yup. After that, I'll show you Formik's hardcore Immer usage.
Interviewer: [43:35] That, Michelle actually wrote. It has a pretty kick-ass 4.8. It's super high on the Egghead scale. Immer course is very popular. Here is Maggie's...
Jared: [43:47] That's awesome.
Interviewer: [43:48] illustrated notes on Immer, something to pay more attention to. It keeps coming up. You're not the first person that I've had these conversations with. There was like, "Immer has really changed my state management game."
Jared: [44:25] I'm going to show you where Immer is absolutely shining inside a Formik cloud right now.
Interviewer: [44:28] Yeah, let me see that.
Jared: [44:30] All right.
Interviewer: [44:31] Why are you doing that? Why so many state management libraries? Why the fuck does Recoil exist now?
Jared: [44:41] That is really cool.
Interviewer: [44:41] It is cool, but why are we having to learn something new every single...?
Jared: [44:46] React is not good at nested lists, nested object, like deeply nested trees. It's too slow. I'm going to end up probably trying to use Recoil in this application because Immer is too slow. Immer and React are too slow. I'll get into that in a second and show you where...
Interviewer: [45:02] I've seen a lot of people say Recoil is just like MobX.
Jared: [45:05] It's not. It's a different structure. Actually, it might be like MobX. I'm sorry. I think it's like MobX-state-tree.
Interviewer: [45:12] Yeah, that's the one.
Jared: [45:13] That's the one, which I haven't used a lot of. It does a very similar concept, but MobX-state-tree does some of the array stuff for you and recoil you, like hand-code it. They are basically doing the same thing.
[45:29] What gets me excited about Recoil is that it's solving the exact problem I'm having with the interface that I'm about to show you. I tried to just use the framework and use research and shit. It's not fast enough.
Interviewer: [45:42] I'm hoping this is your wacky logic gate.
Jared: [45:47] It is. It's a logic gate.
Interviewer: [45:49] Yes. I saw screenshots on Twitter, and I was like, "That is a state I make."
Jared: [45:56] This is the current version of Formik cloud forms. On the left here, we have our representation of the form. Because I'm in developer mode right now, there's a consumer mode. This is a pro mode.
[46:13] This is my app where I'm rendering this information. I'm using the same, exact, similar component library. This is [inaudible] in my local machine. Every single Formik field is totally compatible. You can use your own form field and add type form to your own app.
Interviewer: [46:33] I love your, "What is your favorite form builder?" question. It just made me chuckle. It's precious.
Jared: [46:38] Right. I'm going to show you what I mean by that. On the right here...Let's just swing this over here. I guess my BetterSnapTool is not working. Let's just swing this over. I'm going to do this the old way. Oh, my God. There we go. OK, let's go to...I'll just show you what I mean. There are going to be bindings for different popular UI libraries.
[47:04] I'm working on shocker bindings right now on the right. These are default, but you can bring your own. This is my app. I want to make the short text. I want to change in my app. Again, this is your own component library. It's using regular useField from Formik.
Interviewer: [47:26] This is application code, not Formik?
Jared: [47:28] This is application code. This is my local development thing. You'll see Next.js is happening. It's compiling a name. It's now green. I have total control over, like, "This is my component."
[47:41] What's cool is in Formik cloud, I just add a type form. You can see I pulled up this fork, because you see I'm typing. It's not perfect. It's a little slow. Let's change this to your name. Let's refocus here. Oops, let's go back to your name. I don't know why. It will hot module replace in focus, but let's just change your name.
[48:20] As you can see, I'm using Immer in this part of the code, which I'll show you in a second. This is the multiple choice editor. This is a regular input, or it's a expanding input.
[48:38] Eventually, it's going to have to be a rich-text editor, believe it or not. Each one of these inputs will be rich text, which is complicated, which we'll get to in a second. Each one of these will be rich text as well.
Interviewer: [48:50] Because I want to be able to bold which text, right?
Jared: [48:53] Yes.
Interviewer: [48:53] Is that why?
Jared: [48:54] Exactly why.
Interviewer: [48:55] As a user, I would want that, so I can...
Jared: [48:57] Exactly. This is what gets really fucking annoying, is I want you to be able to...I don't know if this fork has this. If I do this...
Interviewer: [49:11] Oh, yeah, nice.
Jared: [49:13] This should...
Interviewer: [49:14] Like liquid templates...
Jared: [49:16] Yes, this should. Let's see if this works. Yeah. See this React if I change just the view?
Interviewer: [49:23] Yeah.
Jared: [49:25] This needs text highlighting and stuff. It should take the drop [inaudible] different part of an app. What's brutal about this is even though this is super nested in all of this React -- we can use React.memo down here and try performance optimize it -- when I make any changes to this stuff...
[49:46] It's fine right now, but let's say I want this to be an autocomplete input. When I made two curly braces, I want to open up an autocomplete of all of my other form questions. Now this input needs to know about all the other form questions. All that optimization is trying to keep it from rendering when other shit updates.
[50:05] It could be mute if I don't do it correctly. I'm so deep right now. I'm like five levels deep. I'll show you how deep I am. Let me show you how this is stored. This is where we're at. I am this many levels deep. I'm in group one, the thing. I'm in choice. That's how deep I am to edit that label.
[50:29] This is one level deep. That's two levels deep. That's three levels deep. That's a four levels deep thing. That's a huge bitch to have to spread and also optimize for. If I want to make this an autocomplete thing, I need to have and provide the rest of this whole thing or at least the names of stuff and their references like...
Interviewer: [50:51] Do you have to have the whole world in [inaudible] ?
Jared: [50:54] Yeah. It's kind of gnarly, but it's a useful feature. You don't want to carry head stuff. Also, [inaudible] this, all of this is crazy drag-and-droppable and their pages too. Sorry, mouse is [inaudible] .
[51:14] Also, it's drag-and-droppable. It uses natural drop animations and resizing. There are all those React drag and drop stuff, beautiful drag and drop that happens there. On top of that, there's focus management. If I'm in the keyboard right now, I hit the down arrow. Here, my Karabiner -- is it Karabiner Elements that does that? No. What's the one that's -- well, whatever. I was going to show the thing that...
Interviewer: [51:42] Keyboard Maestro?
Jared: [51:43] Is it Keyboard Maestro? Keycastr. There it is. Keycastr. Thank you.
[51:50] OK, that's fine. Can I see this now? Anyways, the -- I need all my keys. Preferences, Display...Can I show all the keys? All right. It's not worth it at this point, but I'll tell you what I'm pressing. I'm pressing the Down Arrow key, pressing the Up Arrow key. I'm pressing Enter. I'm pressing Delete and Delete again.
[52:21] It's all like managed. These are also drag-and-droppable. You can't drag this over there. A lot of shit going on.
Interviewer: [52:33] There's a lot of state being managed, right?
Jared: [52:35] A lot of state happening and of course, you can change the type of question and this would go away and come back. Then the granddaddy of them all though isn't actually this interface. It's the logic builder which I'm about to show you.
[52:52] A logic jump. In order to build logic jumps, I just realized that I should update this.
Interviewer: [52:57] I saw this because you...You go nest and nested on your logic jumps too. A lot of people, they don't do that but I've never seen a screenshot anywhere where you're...
Jared: [53:05] Yeah. This is the screenshot of all screens. Right now, this is going to do if all conditions are met, the question three, is equal to one of these options five. One of these, right? In theory because Formic is a developer tool, the idea is that you should not be limited.
[53:22] I look it, I did an analysis log every single logic thing. I got this design from Salesforce, believe it or not, because I figured they knew what the fuck was up with this. I figured they made a lot of money on their filtering thing.
Interviewer: [53:36] I saw it I was like, "Wow, this needs to be in most of the apps that I use on a regular basis or not."
Jared: [53:44] The way this bad boy works is you hit if all conditions are met, you have the question, it list the questions. This needs to know about all the previous questions, but nothing in front of it. This based on the question type, the quality operator will change.
[54:00] These are set questions, but if it's like an open-ended thing, this will then change to -- because I used a short text -- is equal, not equal, does not contain starts with, end with. Then you can enter a value.
[54:14] This is for one condition. You can have another condition underneath it or you can add a condition group. Here's another condition. It's if and, if I change this to this, it becomes or. This is fun. We're running along.
[54:27] I can also add groups and conditions which work like parenthesis. You can go absolutely bananas to however many deep you want. You can insert and remove and go wild and crazy, all you want to do.
[54:43] The way this works with recursion and I tell you what's fun with state management, recourses state management.
Interviewer: [54:50] Yeah, I imagine.
Jared: [54:52] This is actually stored in a really crazy way. I wrote this engine that can evaluate these kinds of expressions. Then I wrote React, a way for React to understand it and evaluate it. I use Emir to do the updates.
[55:10] If we drop into how the magic is made, if you're going to Element Editor, this is the set of stuff that is in this [inaudible] areas right here. You could see get right side from Element, get default condition from Element, get default right side from Element, get default condition group from Element.
[55:41] These are turning like slices of this AST that I built. This is like, given an Element type, an Element is a question, do different stuff. Again, change this and this is the left side is the question and the right side is this side of things.
[55:58] This shit gets weird too because in certain questions you have [inaudible] other and other can be an arbitrary value. Again, the wrinkles continue. Then you have this recursive function which is basically looking at left side or right side.
[56:11] These are all using useReducer at the top level but then also Ember. This is firing off this nested...In Emir, there's this concept of patches. This is dispatching patches because the state got too gnarly to programmatically update.
[56:29] Patches and Ember work interestingly because you can say, "I want to update at .path," the way lodash.path work. That is what this is doing here. It's saying, "OK, split this," it's going to be like action, index, var. This variable dot thing value and set it to blank.
[56:49] It's doing like deep update and shit like that. In my Element...What's it called? Element reducer? We're all this thing, form state serializer...? Form design reducer. This is all Ember code.
[57:06] Here, let's see the add div. This will be like, "How do I merge a group?" If I want to take this page, [inaudible] page actions, merge with above...
Interviewer: [57:15] It's still pretty gnarly even with Ember, right? If we're using Ember, you would be...
Jared: [57:20] I don't know how you would do it. Look at this, it's insane. Even drag and drop, by the way, was non-trivial because I have dragged and dropped multiple drag targets, multiple drop targets. This is the drag drop code.
[57:37] If you've ever used React drag and drop, it's like move the group, move an element even [inaudible] ignores in here. In the case where the sub-items are re-ordered inside the same parent, that's like this is happening. Then it's like the case where this goes to a new page.
[57:55] Then this and there's another one for if it's a droppable choice, do this here. You could see this code's a little bit...It looks like it's a little more mutable, but if you see other code in this...Let's see, some of the stuff is a clean this equals that.
[58:15] Here, current focus ID equals group ID. This is mutable code, the way mom used to write. That's made this interface super...a lot more easy manage but...
Interviewer: [58:25] You're able to do that because of Ember.
Jared: [58:27] That's what Ember is allowing, yes. I built the thing called use in a reducer. There's also a useEmber that you can install, but because I want to add some debugging in the middle of it, I add this thing which doing like a deep div so I can see current state, dispatching...I'm sure there's stuff, but you'll see which thing it's firing off on.
[58:56] There's a lot of re-rendering happening, but you'll see drag, drop. See if I can pop this thing out so you can see here. Shows you drag, current state, dispatching, next state, state div. Again, this is adding some middleware in our reducer.
[59:13] You can install this. It's called useEmber but I built it so I can add middleware to it, so I can add some logging and stuff. You can see as I just showed you, there's pop-up [inaudible] . You see how much re-rendering is happening.
Interviewer: [59:23] Yeah.
Jared: [59:24] It's too much when I'm moving things. The problem isn't actually moving things, drag and drop is fine. It's when you get super nested here and I start typing really fast. I'm typing really fast, you can't see anything because it's also not updated yet.
[59:36] Because it's recomputing the entire tree and re-rendering everything, because I'm just using useReducer at the top. This is what ReQL is going to help me. What ReQL is going to allow me to do is scoot around.
Interviewer: [59:53] Inside step the tree, right? You're able to go outside the rendering tree and come back into it.
Jared: [59:58] That's exactly right. Also, because it has the power of selectors and you can go up and down with selectors. I explained this today and I can show you what I was working on. This is the playground today.
[1:00:09] You can go up, normalize and denormalize, and capture state. Again, remember, I haven't even done this yet but this is slow and I haven't even pass the entire state tree to this input yet. I need to do that. Plus more information.
[1:00:26] I'm thinking in the future, it's not going to be the current state of this form. We're going to send analytics data. You'll be able to, "Did the user...?" Last page or whatever previous things and that's going to all be here. You're going to be able to do potentially even logic as well, but we need a lot more information here.
[1:00:45] That information needs to be fresh and current, and keeping it current and keeping this typing fast is really fucking hard to do.
Interviewer: [1:00:52] Yeah, because people are typing and nothing's happening. That's like...It's bad.
Jared: [1:00:58] The reason I'm totally comfortable showing this code is I'm about to re-write this entire thing.
Interviewer: [1:01:03] Honestly, good luck anyway. Go, you're not stealing state secrets here. There's a lot going on.
Jared: [1:01:08] Exactly. Even so, this is not performing. This is unacceptable. This is like a free [inaudible] second log because this is using useReducer. We'll flip that -- useReducer -- and we'll make it performant.
[1:01:24] The biggest things that you can do -- I've talked to Ken a lot about this -- to get more performance out of your state management is to shorten your nested tree. This uses Chakra UI right now.
[1:01:37] Chakra is really good and very accessible for simple apps but it suffers, and so does everything that has a theme provider, from death from a thousand cuts. You look at the frame...
Interviewer: [1:01:48] I think you mentioned that. You were like once you get into a theme provider, you...
Jared: [1:01:53] You're fucked from a perspective. You're absolutely fucked because you pay a penalty for every single hook in the context and...
Interviewer: [1:01:59] If you're app's pretty flat, it's probably all right, but if you...
Jared: [1:02:02] For your blog, no one gives a shit. It's fine. If you have super high frequency updating state and you're [inaudible] context to compute some CSS value, no, you're going to be super sad. When you get on level 12 and these things rerender multiple times per second, doing that extra calculation for CSS is too much overhead.
Interviewer: [1:02:30] You had CSS and JS, plus a theme provider, plus all this kind of stuff, and you end up...
Jared: [1:02:35] All the shit. Probably rewriting this application in Tailwind because it's the same look and feel, but also it will just be more performant. Generally removing the Tailwind anyway for performance reasons. You want to keep your state as flat as possible if you're running into performance issues.
Interviewer: [1:02:52] [inaudible] , they're raking it in.
Jared: [1:02:56] Yeah, they are. Sorry, not your state. Your component tree. Your state can be whatever you want it to be, but your component tree should be pretty flat.
Interviewer: [1:03:03] Do you use state machines at all?
Jared: [1:03:04] I haven't gotten to the state machine thing. I probably could have written this interface in a state machine.
Interviewer: [1:03:12] This is where state machines shine in terms of managing a lot of this.
Jared: [1:03:19] I thought about this application as maybe I do want to use a state machine for this type of thing. Certainly for...
Interviewer: [1:03:24] You've built one. To be honest, you've built one. It's just not a formalized state machine. You got a state machine.
Jared: [1:03:32] Exactly. This interface, for some of this more hard-core choice input, if I were to rewrite it again, these choices, which is tons of keyboard controls. There is an earlier prototype that I built that was more type form-like where you could...I don't know if you [inaudible] .
[1:03:51] Type form is more like a document. You can use the arrow keys to navigate all things. I was doing a bit more state machine stuff, so I thought about it. I'm very into honoring the way shit is done in a code base. I already started on this track, so I didn't do it, but potentially in the next rewrite. I'm probably going to attempt to use Recoil.
[1:04:12] Let me pop up in Recoil and show you problem that it's solving and how it will help. I was working on this today.
Interviewer: [1:04:19] I'm sharing with David actually, later this week.
Jared: [1:04:22] That's awesome. Recoil, new thing that's not from React but it's related to React because it's from Facebook. Hilarious.
Interviewer: [1:04:31] It is not the official solution for state management for the React.
Jared: [1:04:35] I was trying to do a form prototype but I couldn't figure it out, so we're not going to show that. I was working on another one that I tweeted about, maybe. What I wanted to show is the problem that I'm having, and that probably many of you have. You have some data in your API, like a list of form questions or something.
Interviewer: [1:04:54] Maybe so.
Jared: [1:04:55] Maybe so. Who knows?
[1:04:56] This is just the simple stuff. I have a normalized function that's going to return a list of IDs, and then this object that's by ID. You can see this is what a normalized state is. Let's zoom in on that. You have initial data here. When I normalize it, I've got a list of IDs.
[1:05:12] Then I've got an object called by IDs that is keyed by the unique identifier, which is the ID, in this case A. Then it's just this object itself. If I want to get a value, get item state...This is a classic Redux selector. Classic [inaudible] . By ID state ID. It's an [inaudible] lookup. It's fast. You don't have to search for it. You're not looping through every item in the array. You're just getting it. Boom, done.
[1:05:38] If you need to reconstruct the array, you can map through the list of IDs and then do that lookup. That's what I'm trying to accomplish here, but it wasn't clear from the Recoil docs how to do that. That's where I was like, "I don't know how to do this." I just built this little test run. Let me walk you through it.
[1:06:00] We have data, this normalized helper. You've got this atom in Recoil. I don't know why they call it an atom. I thought they would have called it state, but whatever. It's confusing. It's a piece of state. It could be anything you want it to be.
Interviewer: [1:06:12] Atom is something, the way I'm familiar with it from, is from the little schemer, scheme stuff back in the day. They used that terminology. I don't know for sure if it's related, but that's where I've heard it before.
Jared: [1:06:27] There you go. Then that makes sense to you. To me, I probably...
Interviewer: [1:06:32] I don't know about that.
Jared: [1:06:34] Then there's [inaudible] like...I'm going to make up stuff. I'm going to pretend we can make shit up.
Interviewer: [1:06:44] New names. Cool.
Jared: [1:06:45] You have atom. Atom's cool. Then there's selector and selector family. Selector, as you probably heard from Redux, is a memoized function that takes some sort of state thing and returns an expensive computation of it, a computed value of it, filtered to-dos or something like that.
[1:07:05] Recoil has that too, but also [inaudible] selector family, which is a parameterized selector, which is instead of me writing returning a memoized selector, it's just going to do the memoization for me, and whatever I pass it, it will assume that it's unique. This is the parameter of ID. It'll give me a new selector for each ID, which is what I want here.
[1:07:32] The goal [inaudible] I have a list of...Here, let me show you. I have a list of counters here. I want each counter to be editable. Then I want to be able to send this list back to my server. That's the end goal. I can click this and click this, and click this and click this. When it's done, I can capture the current state. That's what I want to be able to do.
[1:07:58] I have this list of data. Again, by ID state, ID state. These are atoms. Then to get the item state, this is called selector family. I think a better word for it is synthetic state. I don't know. The selector API in Recoil has a get but then an optional set.
[1:08:20] It's the optional set that really bugs me out because it's computed. Selectors are supposed to be computed values. So how the fuck are you supposed to set them? It doesn't make any sense if they're computed. If it's derived, then how is it setable. This is like brain fart.
[1:08:35] That seems repetitive. Shouldn't I be setting by ID state here? Actually, that's what I'm doing. In selector family, you can say when you set this selector family, but in my mind, I'm calling it synthetic state or synthetic atom. In my mind, it's fake state. It's like a shadow state.
[1:08:52] You say for this thing that I'm going to call item state, under the hood, do this. Under the hood, set by ID state, which is what we want. This is your classic spread. Spread this for this ID, which is going to be the items ID. Set to the new value. That's a full replacement. I'm fully replacing this on every keystroke.
[1:09:17] If I wanted to go one more level deep, I could make an item value state that would be synthetic version of count or item count state that would be deeper if I only wanted count to update. I'm fine for the purposes of this to update the entire object instead of just the one key value.
[1:09:33] In performance [inaudible] situations, you want to be able to drop down and just the only component that's going to only update for that one nested count. That's where Recoil is going to shine, because you can isolate super nested shit and not have it...
Interviewer: [1:09:46] You could take it just a very precise slice of state and target it and ignore the rest of your whole tree and all that.
Jared: [1:09:53] You'll notice that where things are rendering, it's just this thing. These things are not rerendering. If I take away this memo on the counter...Where's my counter? Take away this one memoization thing, which is taking ID, now you'll see this extra line here. That's because everything is rendering at all times.
[1:10:14] Now that I've memoized this counter, it's just going to update when part of this ID changes. Really, it's this part right here. It's actually this part. Just when this changes, this is the thing here. Why are we normalizing in the first place?
[1:10:30] Imagine if it was just here, one, we'd have to look up. You would find index or something to find it. Then you have to do that whole array thing, find the new thing. It's annoying. This is just a really easy lookup thing.
[1:10:43] What I was confused about with Recoil is I have this nested list of stuff, how do I get it back into place? I have this normalized thing. How do I denormalize it or normalize it back? How do I put it back? The updated version, how do I get there?
[1:11:01] That took a second to figure out. Basically, if we want to reconstruct the original list, we build another selector. We take this state and we wrap it back. We do get ID state and map it back to item state. That spits back out the normalized Recoil state.
[1:11:18] In this little thing click to capture, you can access it. I have to look a bit more about this, but there's this extra hook called useRecoilCallback which lets you take a snapshot. Why this is called getPromise, I don't know. getPromise accepts one of these atoms or selectors and gives it back to you at the current moment in respect to a click.
[1:11:44] I can show it to you. I know why they're doing it this way. Recoil and Suspense are like best friends. That's why this is...
Interviewer: [1:11:52] There's the Concurrent Mode and all that fun stuff.
Jared: [1:11:55] They have undocumented link stuff in Recoil source code that lets you wait for shit to happen and get the next state. Also, it persists after URLs by default or local storage by default. Very easily, it's baked into this.
[1:12:08] Recoil is going to shine the brightest in an application like I have like Formik, or if you're building an editor like Figma, or if you're building shit that's super distributed and super high performance and has crazy amounts of updates because you're rendering a lot of shit on the screen.
Interviewer: [1:12:24] It's a criticism of React too that it doesn't handle that stuff very well. I've read that recently. There's two sides of it. It's either you don't need React at all, there's the sweet spot, and then there's React is not performant because of the deep trees for some apps like you're building. It's just not great.
Jared: [1:12:42] If Recoil didn't come out...
Interviewer: [1:12:44] You would had to make a Recoil?
Jared: [1:12:46] I did. Formik 3 has a Recoil thing built into it because this is a big problem. I might look at that. Even so, if I were to go rebuild Formik Cloud today in the dashboard, yes, there's a lot of nice, fun interactions and stuff and React is awesome.
[1:13:06] If I were to put my big product hat on, I would probably build most of the app in MVC Rails. Then the part that's super intense of MVP, drop down to Canvas if you're thinking about actual bread and butter stuff. Get the CRUD stuff out as fast as possible, and then focus your energy on the hardest core stuff.
[1:13:32] Instead of React all the things, people need to ask yourselves, "Do I need React in all of my app in settings, or can I also just..."
Interviewer: [1:13:42] Maybe not lean into "I'm a React developer" so hard all the time. I'm not telling anybody what to do.
Jared: [1:13:49] No, [inaudible] . I'm just saying next time you're like, "I'm going to build this gigantic single-page application," think for two nanoseconds, do you need to build the entire thing in React? Do you? Would it be faster if you just banged out all the minutiae, [inaudible], settings and all the stuff in Rails and then popped in React the actual bread and butter?
[1:14:07] I don't know what you're doing, but maybe. Again, it's not going to make a difference because you don't have that highly interactive...Maybe for the video.
Interviewer: [1:14:15] It even makes difference on our app. We build a React app for a lot of reasons, but sometimes I sit down and I'm like, "What if I was sitting down with DHH and was asking his advice on how to build an app? What would he tell me and why?" I'm still going to do what I want to do. We all are. People have these opinions and people have deep opinions. People build apps in certain ways for lots of reasons.
Jared: [1:14:41] My thinking now is somewhere in-between. I think React is great. Also, you've got to think about hiring needs and also other shit, [inaudible] .
Interviewer: [1:14:47] It's like if you're going to build an app in ClojureScript.
Jared: [1:14:51] Right. Just because it's the best doesn't mean it's right.
Interviewer: [1:14:53] It's a nice filter though too, which is an interesting.
Jared: [1:14:57] This is tied in Suspense. It seems like it could solve a lot of the problems that React has and suffers from, which is it's really slow at deep nested updates. Parent-child communication is hard. The Context API is fundamentally flawed because it doesn't let you subscribe to slices of content. It's all or nothing. That's not good for highly performing applications.
[1:15:42] It's the same concept. If you think about React. Let's scroll to a different part of the screen. How do get rid of this browser thing? I think about React as f(g(z(b(x)))). This equals UI. This is the React part. This is like createElement and shit in my mind.
Interviewer: [1:16:08] Carried?
Jared: [1:16:08] Remember in math class where it's f(x)?
Interviewer: [1:16:11] Yeah.
Jared: [1:16:11] [inaudible] first solve for g(x), then put g(x) as the input to f(x). That's what I'm thinking. This is a big function. Yeah, you could carry this, but the point of this is start the innermost thing, then the next most thing, then the next most thing. This is simplification in the final one. That's like createElement or rendering either way in and out. That's how I think about this.
[1:16:50] When I think about props and state, I think about this is a function of this, is a function of this, is a function of this, is a function of this. That means that you can only go in these two directions, in and out in my mind. Context lets you go from here to here without necessarily passing all these arguments. It can just magically show up in B that was defined in F, and that's fine.
[1:17:17] In my mind, Recoil and other solutions are like no actually, let's keep the state out here and shoot arrows into these things from the side, or underneath or over. Wherever you want to put it. It's not in this equation. It's outside of it and it's going to inject it into where it needs to go so that it updates faster. It's my mental model of how it works.
[1:17:39] In the Recoil.js, even there. They're a cover of this. That's their concept. You have this tree, and it's covering [inaudible] . You have this tree underneath. That's regular React. Then Recoil are going to be the atoms that are above it or on a different dimension of it.
[1:18:00] Which is also how Redux works technically and also how every other state management thing works too, but this is a little bit more perf optimized. There's also some built-in primitives for Suspense and serialized ability, and link sharing, and URL persistence and shit that seems very thought through.
[1:18:17] Half of it isn't documented. There's that, but I'm very excited about it. I think it might work for me. I'm not sure yet though. We'll see. That was a whirlwind of stuff, but hopping that I gave some people some sense of how I think about state. I wish I had all the answers. The biggest one I think is normalization is...
Interviewer: [1:18:41] You could be a state management millionaire if you had all the answers.
Jared: [1:18:45] I know. No one does. Also, the...
Interviewer: [1:18:50] That silver bullet thing really comes into...Everything has trade-offs. There is no perfect solution.
Jared: [1:18:59] Look at me. I'm me. I spoke at React Conf. I know a shit ton about React. I built a product that I'm supposed to pay rent with, and I can't use it because I didn't get my state management right because it's not fast enough. If it's confusing, it's confusing for everybody. That's what makes this hard.
[1:19:20] What's important too is make sure that the rest of your app...I find that focusing anything other than state management, I'm wasting time. I don't want to waste time on tooling. I don't want to waste time on styles that much. How it works, how it's designed, and then where state is going. That's where I want to focus my day on.
[1:19:43] I find myself thinking in state. In my mind, state is this weird hybrid of TypeScript interfaces. I don't know if you've ever...
Interviewer: [1:19:52] I understand that. I get that. I haven't used TypeScript very much, but I can feel where the static and the typing and all that makes...It's metadata on top of the graph of state inside of your application.
Jared: [1:20:09] If I pop open last bit, if I think in my form design reducer. Form state serializer. This is my more hardcore normalizer. That's how, like I mentioned before, was a layer list. This is how I'm thinking. Its tree item has children. It's expanded the list of children, the IDs of the children, the data.
[1:20:38] When I'm deep in thought and taking hour-long showers. I'm like, "How is this going to be better, this, that and the other thing. Will this be faster than the next?" Again, there's no silver bullet to any of the stuff. It's hard as fuck. If it was easy, everybody would do it.
[1:20:57] State is why React is so popular, by the way. It's just so much better at it than everything else, or it was. I don't if it is or isn't anymore, but it was groundbreaking because it removed time from the application. You could just worry about the state. You didn't care when shit fired off past the point. You just cared about what, not how. Just what. Not when, just what. That's huge.
[1:21:26] That's how I think about it. Anyways, man. It's good to chat and give away the goods here. No, I'm just kidding. This has been fun. I'm hoping Recoil is dope. I think people are shitting on it for no reason. I'm willing to give this thing a chance.
Interviewer: [1:21:44] I don't see much of that. I think people are just shitting on new...It's that fatigue thing rearing its head. I like and I'm interested in new stuff because one, all my solutions are going to be garbage eventually.
Jared: [1:22:01] Also, I don't know about you, but it took me a while learning Redux. It did not make sense at all. It took me multiple tries. I did not get it at first. Flux was over my head too. I eventually, after...
Interviewer: [1:22:14] It's very similar, some command pattern stuff that I used to use in the Flush days, which is weird. The KCD, let's give it a new name. That is unique [inaudible] . Nobody is reading the "Gang of Four" book and using those design pattern names, even though they're super relevant even today.
Jared: [1:22:37] Everything about React has been implemented in games.
Interviewer: [1:22:41] Oh, my God. Did you see the new Unreal Engine stuff? We're over here [inaudible] bullshit. It's like you're living the game now. Then this is where we are in Web development.
Jared: [1:22:55] We're just lucky those game developers love gaming so much and don't try to build the actual business applications.
Interviewer: [1:22:59] Exactly. They like the crunch time, horrible hours, and low pay. We have to go here and hammer out forms.
Jared: [1:23:07] CRUD apps and forms, exactly. It's hilarious. Hopefully we don't catch one of those.
Interviewer: [1:23:13] Make a better form builder. I love it.
Jared: [1:23:17] That's the plan. Hopefully, this thing will be, the new version of it, will be very widely available some time in June, the newer version, which will be very exciting. I'm very excited about Recoil. It's almost like a gift from the universe. I was like, "Oh, my God. I was inventing the same thing."
Interviewer: [1:23:38] Good timing too, sounds like.
Jared: [1:23:40] It seems to be very much inside baseball, the code base. It's very [inaudible] .
Interviewer: [1:23:45] Oh, yeah. [inaudible] said they've been using it for a year. They've got a lot of stuff going on in Facebook they're not really cluing us in on at this point. They learned their lesson with hooks. They're like, "You know what? Fuck y'all."
Jared: [1:23:58] First of all, half of it, you knew it was raw from Facebook because half of the shit on the documentation site wasn't even exported from the actual library properly. Another half of it isn't documented or available. There's a lot of unstables that they added in on the side.
[1:24:22] You could tell it's really used. If you read the code, people who've written it have a deep understanding of both React and Suspense, and also Concurrent Mode because it does things that are interesting in relation to...The thing that I was prototyping was all synchronous. This thing, your selectors could be async. You can make requests and selectors.
Interviewer: [1:24:49] Oh, tricky, tricky.
Jared: [1:24:51] It doesn't care.
Interviewer: [1:24:52] It gets to that promise thing. I don't know why they named this, but it's because it can return...
Jared: [1:24:57] It can return a promise. It's not just a straight up O(1) look. It can wait, and also it will suspend if you make that shit throw. There's going to be a Egghead Recoil course. I might have to do once I figure out how to do it once I figure out how to use it, but it's going to be gnarly.
Interviewer: [1:25:14] Honestly, there's a lot of orange juice in that brain of yours that we could extract into all sorts of fun courses.
Jared: [1:25:22] We've got to tap.
Interviewer: [1:25:23] You've got a ways to go. I think you got a lot on your mind until then, but look forward to.
Jared: [1:25:26] Hopefully someone knocks that one out the park though. Maybe Dan will do it. That would be pretty funny.
Jared: [1:25:36] How's that going?
Interviewer: [1:25:37] It's going great. I don't know. Have you signed up for it?
Jared: [1:25:40] I haven't. I have to.
Interviewer: [1:25:43] It's just emails. We're sending out emails. There's a little typeform involved.
Jared: [1:25:49] Once I get my quiz shit together.
Interviewer: [1:25:56] Our next phase of that is getting through the manuscript portion of it. I think the timing will work out really well. We've discussed it anyway. What you're doing is perfect, plus I think you'll be interested in what we're up to. To me, this is what I've been looking for.
[1:26:13] What you're building is so nice and it's going to be tuned and solves the problem for us that I was almost going to build myself. Now I feel like I don't need to anymore. That's nice for me also.
Jared: [1:26:23] The cloud form thing is going to be game-changing for automation.
Interviewer: [1:26:31] I don't know. It's pretty close to the database for us. I see all sorts of fun stuff.
Jared: [1:26:39] I'm trying to keep myself from finishing off the rest of Airtable, but I may end up having to build this concept of sheets. I'm going to hopefully hold off on that to V 1.1. For reasons we can discuss over, it may turn into an Airtabley thing. We'll see.
Interviewer: [1:26:59] That makes a lot of sense to me, actually. Airtable, it's a database, which is a sheet.
Jared: [1:27:05] Which is actually a form. It turns out that in order to do the editable IDs of a field...Basically, the problem in the V1 of this was if you deleted a question or if you made a question, you delete the question, you lost all your data.
[1:27:21] What if you just want to rename a question or you want to rename a column in your results? You're trying to rename a question. In order to do that, you just store a reference. The name is just this writable thing. When I did that, I was like, "Oh my goodness gracious. I just invented Airtable."
[1:27:40] Instead of storing the actual name of the column and storing a reference to something, and then I can look at the editable, oh my God. I just made editable columns, which is the same thing as editable field names.
[1:27:47] [inaudible] . Fuck. [inaudible] rewrite there, it will be a little bit more Airtabley at first, but there's all sorts of stuff that's going to be fun and great. I'm hoping that it is.
Interviewer: [1:27:59] It's a good problem. It's a good project. It's just appropriate for your brand too. I feel like, just the way, from our conversations, it's a good, solid, meaty problem that can expand in all sorts of directions to help people. It's valuable. [inaudible] credit cards makes a lot of sense on that. There's plenty of competition but none of them are...That's a good thing, to me.
Jared: [1:28:24] It confirms that there's actually a need for forms and form builders.
Interviewer: [1:28:29] It's all forms and lists.
Jared: [1:28:31] Forms and lists and functions. That seems to be the next feature of little things, and auth, too. We'll see about that. We'll do another podcast on auth [inaudible] . Hey man, I've got to jump and run for dinner. This has been super fun.
Interviewer: [1:28:46] All right. See you, man. Thanks. Appreciate it.
Jared: [1:28:47] All right. Later, dude.
Interviewer: [1:28:48] Talk to you soon.