David McCabe
David McCabe
UI Engineer at Facebook. Author of Recoil.js
Fire-side chat on Recoil
React Summit Remote Edition 2021React Summit Remote Edition 2021
34 min
Fire-side chat on Recoil
Thank you so much for having me. It's definitely exciting to get to chat. I regret that the place I'm staying doesn't have a fireplace. We'll just have to pretend. I just moved to Prague now because I've stayed during the holidays in Romania and now I'm in Prague, but here it's much better. I'll have to say the weather is much better. I'm so happy to have you here. I was listening to your talk about Recoil.js and it's so nice. There are so many state management solutions out there, but Recoil, since it's coming from Facebook and from you especially, it's really great to see that. But before anything, could you please give us some details about who you are, what you do and what's your daily job basically? Sure. So my name is Dave McCabe. I have worked at Facebook for a few years now and most of that work has been focused on performance analysis tools. So probably most of you have used the profiler in your browser where you measure what's taking so much time and why things are slow and where the code is spending its time, that kind of thing. I spend a good deal of time building tools that are like that, but they don't just take a single measurement. They're based on many, many different measurements that have been taken from production and then aggregated. So if you can imagine a profiler like that, but everything that you see is a statistical distribution instead of just a single measurement. And you can do different analyses based on what variables might be affecting performance of your app. So whether it's the type of device that somebody is using or things about the user, maybe something slow for people that have a lot of friends, different types of things like that, or whether it's affected by a code change, configuration change. So I spent quite a bit of time building stuff like that and Recoil was extracted out of an app that had certain pretty specific needs and we decided to pull that out and make it a separate library. Wow. So many things. Yeah, I'll not say anything about myself now. I would like to just shut down the camera and just pretend that. Why do you say that? I don't know. I don't have that. Cool. So since I don't see any questions on the discourse, if anyone has any questions, just address those and we will discuss. But I have some questions prepared. Okay, great. And the first one is that I saw a couple of times on Twitter especially is the following. Is this meant to replace Redux? I would say that your first choice if you're looking to replace Redux is to see if you can just do what you need with React only or with React and Relay. And there's actually a lot of advantages to that if you don't have a separate system. So I would say that if you're hitting certain performance limits with that in particular situation so we can talk about with Redux, then Recoil might be a good option for you. Great. Now I see a question coming from Jordi, but it also came earlier from BKG. They're saying that what is the status of Recoil? It seems to still be in beta. It seems like it would solve our problems, but it's hard to convince others because it's a beta product. What are your thoughts around? Yeah, it's being actively maintained. We actually just put out a release about a week ago that has some really nice improvements and more is on the way. It's being used by a lot of different things inside Facebook. So we're definitely, we depend on it. It's not going to disappear. But it's kind of considered to be an experimental project because it's not something where the company is saying we totally endorse this, this is what everybody should use, which is the case for example with React. React has a very, very high quality bar and it should work for basically any app that you want to write. We think you should do it with React. Same is true of Relay. Recoil is more of something that could be useful and if it's useful for you, then we're very happy to make it available. But what its really long-term future is, is unclear. All right. I don't look at Recoil and say this is definitely the answer, capital T, capital X. Describing those little updates, I saw recently that Recoil was bumped to 0.2, right? And can you just please tell us more about the improvements that you guys did or you did in general and what bugs were fixed in general? Like a highlight of what happened. Sure, sure, sure. The two main improvements in 0.2 were a new implementation of selectors that is much more robust and fixes a bunch of kind of bugs that probably most people wouldn't have hit, but you know, you could. And then it's a lot faster if you have a really large number of atoms. Like if you have thousands, tens of thousands of atoms, it would bog down. And now that should be a lot better. Which we actually use in certain apps that use Recoil. You'll have like, let's say you have a document and every element in the document is represented by an atom, right? So that's the kind of thing that it's meant to be good for. And that actually works a lot better now. Regarding the selectors, it's a, so something that's unique about Recoil selectors is that they can have dynamic dependencies. So every time you execute the selector, it's not that it has statically declared a set of other atoms or selectors that it depends on. And just to maybe step back, if people aren't familiar with it, a selector, the way we think of it is a function, it's a pure function of some other state that just has information about what state it needs. So that when that state changes, that function will be reevaluated. And so that like the components could subscribe to state, but it can also subscribe to a function with state, if that makes sense. So you end up with this graph, this like data flow graph, and that things are flowing from state down through these functions and into components. And most things that do something like that, the shape of that graph is known ahead of time. But in Recoil, it can actually change. It's a function technically of the state. So it's not like chaos. It's, you know, at a given state, the graph will have a particular shape. But you discover that by evaluating the selectors. And when they run, can say, I need this data, I need this data, but that can be conditional. So in one state, it subscribes to some data, and in a different state, it does not. So far, so good. The basic way that you would want to implement selectors is that like, if you're just, you know, sitting down, thinking about how to do this, you'd have like a cache where the entries are like sets of dependencies. So it's like, you know, these were my dependencies, these were in this, they were in this state. And so then here's the value that I got. That doesn't actually work if you have dynamic dependencies, because a particular evaluation of a selector, if it's asynchronous, that this set of dependencies it has, and hence the cache key that it should have, will actually change over the asynchronous execution of that selector. And so basically, it was just this big kind of redo of all that to separate those concepts. You have like the execution of a selector, and then you have like the value that's been evaluated for a particular state at a particular point in time. And those are two different things. A lot of things happen, actually. The upshot of that is just that there was a lot of edge cases that happened with async selectors that are now fixed. So that should be a really robust feature. Okay, so related to selectors, Jiroch94 asked a question, are there patterns or gotchas when creating selectors that would cause performance hits or unneeded renders? Yeah, I think the main thing to look out for that is that recoil is based on the idea that you would separate out your state into little atoms that are individual. Compared to if you're thinking about it sort of the way you might think about it and say Redux or some other systems, you have a big like store with all of your state in it, sort of one unit, and that is updated atomically. And then you have selectors that are pulling out little parts, like this bit is going to be used by this component, this bit's going to be used by this component. So they're sort of selecting them, right? That approach eventually hits a scaling limit because as you have in selectors, whenever any state changes, you have to evaluate all of those selectors again to see whether the things that are downstream of them need to update. So you don't want to wind up in a situation like that. And recoil doesn't optimize that at all, if that's what you're trying to do. So it will not bail out early if you have a selector that's value doesn't change. So the way that you want to do it in recoil is to already take the things in your state that would independently be updated and separate them out into different atoms. That's the main thing that I see people running into. So you want to like break up the state into little pieces. And then recoil does provide you with an API that'll let you update them together as a single unit. Great. I have another question about the new update. So recoil previously was dependency free, right? There are no third party dependencies. And now in 0.2, you've added the HRA map tree plus package. Can you please expand on that and what is the purpose of it and why is that helpful? Oh, right, right. Yeah. So that goes back to, I said there's two changes in 0.2. I talked about the first one. The second one is just the improved performance. And that just comes from having a data structure that lets you do something that's like an as if copy. Like you're taking a big map or a big set and copying it, but without actually having to do that. Because that'll eventually slow you down a lot if you're just taking a built in map or something and copying it. And so that library implements a data structure that lets you basically if you think of things, you can, this is probably easier with pictures. And if you Google for like hash trees, you'll see these. But basically what you want to do is divide up your structure into sort of segments that are then in a tree. And if you want a new copy of the whole tree, you just need to copy the segment where the changes happen and like all the nodes that point up to that. It's the basic idea and everything else. You have a new tree, but it ends up most of it goes down to the same sort of base level structure. And so that's what that implements. And yeah, it's just for improved performance if you have a really large number of atoms. This actually reminds me in the past, I was looking at Baobab JS, which is, are you familiar with Baobab? It's doing the same thing. I don't know that I am. Why don't you talk about it a little bit? Like the tree? Yeah, exactly. So it's, but it's based on indexes and yeah, it's basically, it's like a tree, right? And you have leaves and whenever something will update, we'll just trigger down the road. So whoever is listening to those changes will receive an update. But it's so cool to see like great and like so valuable third party libraries, which are like really tiny in size and that can do so, so many good things for recoil and also for other libraries, right? Because it's an implementation. Yeah, you know, a lot of this stuff came out of the, I think it was kind of a closure community, the closure of the J programming language really innovated a lot of stuff around these persistent data structures and sort of using them in practice. A lot of the, you know, I mean, if you look at recoil, it definitely, you'll see a resemblance to some of the stuff that exists in closure script and that kind of thing. And it's really cool to see that getting adopted in JavaScript, people figuring out how to use that stuff. Of course, the language doesn't really, you can't implement data structures like that at the full efficiency of the built in ones. They're implemented within the VM, but for certain applications, they definitely have a lot of value. So it's great that that's seeing adoption. Yeah. Thumbs up for that. I have another question from Renee. What is the advantage of a React context provider? Compared to what? Compared to recoil, of course. Oh, okay. Well, I think that you should, for most things, you know, if you, for most apps, you don't need to involve another library. You can just do that with React. And a React context provider lets you have state that's sort of shared within a whole tree that is efficiently handled by React. There's not a lot of overhead to doing that. And then it'll work with different, you know, potentially future React features. So like if you look at things that are coming down the pike in React, like server components, that type of thing, if you're using built-in React features, you are guaranteed to have compatibility with whatever new features come out. If you're using some other library, including recoil, you know, it might or might not be compatible. So I wonder if they have something more specific in mind with their question, but that's just sort of what comes to mind. Yeah, we will wait for Renee to pose there. But yeah, it's more like maybe the communication between like components. We are waiting for him just to add more details, maybe. Another question that popped two times actually was the state of the server-side rendering support in recoil. Guido actually asked this, and Bhuttar Gak, hopefully I have not misspelled it. If you can add something about SSR. Yeah, we do support it. I'm not actually aware, I haven't heard from anybody using it. But we do get a bug report every now and again in that scenario. So I assume that people are using it. And we try to fix those bugs. So basically, recoil provides an API that you're probably going to want to use if you're doing this called initialized state, which is a prop of the recoil route. And when you use that, it uses that state on that first render. And so that's what's going to be used for SSR. Great. Another question from JROC94. Can you unload atoms? If you are dynamically creating atoms by ID and you no longer need any of them, are they trapped in memory? Just before you answer, I actually went to recoil.js docs, and you are actually mentioning there that is something that you are going to work in the future. But worth saying maybe you can say more about that. Yeah. So currently, you would do that by manually deleting them with a hook that is called use reset recoil state. And that will clear out that value. It's sort of resetting it, but it's really deleting it, resetting it to the default value. And so that's what you can do at the moment. And then we have some changes coming out soon, hopefully, that will automatically free atoms. So you'll opt into it on a per atom basis. You'll say, I want this atom to be garbage collected, basically. And then when it's not being used by any components, it will get deleted. And we're using that internally and hope to release that in open source pretty soon. There is a slight API change. So there's going to be like one release where you get a warning that you need to change a thing, and then another release where that feature will be turned on. Really small change. Shouldn't affect most apps, actually. Amazing. Another question is where can I use recoil.js? And in your opinion, what's the best use case of it? If you can expand just a little on that as well. Sure. Basically, you want to use it in situations where you have a bunch of different pieces of state. Like an indefinite, not like a fixed number, but some variable number of different pieces of state that affect sort of distant leaves in your React tree. The basic assumption in React is that most updates are either going to be small or big. So either you're like updating one button because you clicked that button, or you're going to a different screen and you have to re-render everything. In most apps, most updates are in those two categories, and both of them are very efficiently handled by React. Where it doesn't work so well is when you have things that are updating quickly, but they're in distant parts of the tree. It's not the whole tree. It's not one part. But it's like over here and over here. That's where you want those sort of more subscription-based updates from some piece of state that's not in a particular part of your tree. So you can use it in situations like that if you need it. But I'd really suggest you try to just build with React and see how far you get. And then you can kind of add Recoil in as an extra ingredient if you hit a limit. The other thing you might want to look at that I'm surprised isn't more popular in open source is Relay. It's another Facebook library that we use very, very heavily at Facebook. And it has a really unique power, which is the ability to analyze a tree of React components, see what data they're going to need before they run, and take all that data and roll it up into a single query. And then you can actually start loading that query while the client is still downloading your JavaScript. So before the client even has the code to execute, to know to run the query, you're already computing that query, hitting the database with it. And obviously, you can't get faster than that. So if you're loading data and thinking about using the asynchronous selectors in Recoil to do that, see if you can do it with Relay first. Because if you can, that's definitely always going to be faster. Amazing. Thanks for the tip. I'm pretty sure that whoever is listening now and will listen in the future, they'll take a look at Relay as well. I have another question from Mr. Oz. Is there a better way to refresh async selectors than using request ID atom? Like, request ID is request ID, request ID plus one, which returns request ID plus one. Yeah, I mean, that's exactly the way I would do it. If that's converse, I mean, you can take that whole pattern and kind of wrap it up into something that will generate those for you. I think we actually have one of those. I'm not sure if it's open source, but it's very easy. You can write that once and that's the way to do it. Because that maintains the concept that a selector is a pure function of some state. So then when you get into things like, if you're going to do time travel debugging or something like that, or just kind of looking at the system, everything is pure function. It doesn't vary over time. You're explicitly modeling time, but then that's part of your explicit model that you could manipulate. Does that make sense? Yeah, I remember when I first got started with React, which was almost eight years now, there were mixins, there was no context API. There used to be a context API, which was hidden somehow. And you need to dig really deep into React internals. But I remember we had such a big tree that at the end, we had so many properties that were sending down the road and basically cascading those. And we had so many unnecessary renders because in the middle of the tree, the component was basically just a proxy for those properties, because we are using the methodology HATEOAS, which is basically like an API explorer. So an API response will give you more endpoints where you can fetch more data based on the current resource. Basically, just think about HATEOAS as a user's endpoint API that will give you user one to three URLs that you can fetch forward. So we are having basically a representation of the API by components, React components. And I remember that everything was really not that performant. So we had to do like shoot component, update tricks and pass somehow on the global state. But then of course, Flux and Redux appeared and like this state management solution. And nowadays it's Recoil, which is looking really promising. It's really easy to use. I just went to the docs and I could really easily digest almost everything. Not the internals yet, but the overall API seemed really easy to go through. Speaking about getting started. Yeah, I just, sure. I was just going to say, thanks for that. And I'm happy to hear that it's easy for you. It's been very cool to see since React, React really changed the way that one thinks about user interfaces. Like there was a paradigm that was basically set in like the 1970s with the Xerox stuff, you know, object oriented, you know, that whole way of looking at things that was carried through basically until React was invented. And now it's been this Cambrian explosion of like people figuring out how to actually use the new paradigm effectively. So it's been fun to kind of see all the different iterations of that. But what were you going to say? Since I'm a really huge fan of React Native, am I able to run Recoil in a React Native environment? Yeah, it's something that we don't use, but that is supported. So there's some folks in open source that have contributed to that and are trying to maintain that so that it works. It's part of our tests. We do a release. We make sure it works on React Native and that kind of thing. So in theory, yeah, it should work no problem in React Native. So happy to hear that you're using that technology as well. Yeah, I'm a huge fan. I actually had access to it since it was in private because I was blessed that someone went to React JS conference when it was announced in 2016. So I'm playing with it since then. I truly love it. Actually we are using it in Skype as well. So yeah, we're using React Native and Electron, but for state management, we have our own solution which is open source. It's different compared to Recoil, but yeah, this is what worked for us. And it's pretty hard nowadays to revamp everything or rewrite everything, right? Because it's a pretty huge application. And rewriting is not in general something really good. So yeah. Yeah, it takes an enormous effort to do that. Yeah, exactly. So does it work? You need to also do some measurements. Does it work or not? Speaking about getting started, maybe there are people watching us that would like to start or getting started with Recoil. Do you have any examples or good practices that people can follow or look at? Yeah, well, there's a website. If you go to recoiljs.org, there's documentation on there. And then if you click on external links, there's a section of that website. There is a link to some videos that somebody has made actually that are pretty high quality and actually walk you through how to make a drawing app with Recoil. And I think that's a pretty good introduction to using it. I recently came across learnrecoil.com. Yeah, there is a developer that's... Everything is for free. He's going through everything that you need to know about Recoil. And he's actually trying to recreate Excalidraw using Recoil. I think that's probably the same thing that I was referring to. So that's linked to from the Recoil website. Exactly. Yeah, it seems like really good work. Let's see if we have any other questions moving to Basecamp Q
&A. Another question from Drys Capon. I think we discussed it, but just to ground this up, it's should we be worried about the experimental flag, can Recoil be used in production? I mean, I think you need to weigh the benefits and risks for your particular app. So it's not like it's going to vanish. The code that's out there you need to use. We use it a lot internally. I mean, proportionally because Facebook is so big. It could be a tiny fraction, but still be a lot of different apps. But we use it in a bunch of places. So we kind of have a dependency on it, and we'll probably continue to support it. But it doesn't have the same level of support as something like React. So I guess I can't give a definitive answer, but that's sort of what the status of it is. There's a bunch of people that work on it. It is kind of a side project for all of us. But we use it for apps that we need to keep running. So it's not going to go away in the foreseeable future. Yeah, it's really nice to see that everything that's open source by Facebook, it's actually used inside a Facebook app. And this means a lot because even though it's experimental, it's used in production anyway. Even though it's A-B tested and stuff like that, but it's something that it's in the wild, how developers used to say. And another question came from M. Botes. Would you recommend Recoil for beginners or later have them learn the others first? I think by others means React State. Right. Yeah, I think that if you're starting out with React, just use React and you can get really, really far. And for most apps, that's all you need. So I would say you don't need to worry about other state management systems, Redux, Recoil, all that. These are for pretty specialized things. If you look at Facebook.com, it's all just in React. You can make a really, really complex app and in almost every case, that's everything you need. And then if you need to load data efficiently from the server, you can add in Relay. And if you're in a case where you hit some performance bottlenecks, you can't figure out any other way around, then you could think about doing Recoil. Great. I think we have time for one more question. It's from Mr. Woos again. Are there plans to incorporate Recoil into React DevTools? We are actually releasing our own separate DevTools for Recoil. And I think that's in open source, but not quite on the Chrome store, or whatever it's called. But hopefully will be soon. And it's pretty cool. It lets you see history of all your Recoil states and actually shows a graph of how your data is flowing through selectors and which ones are hot, which ones are being re-evaluated frequently. So you can say, oh, the selector, I need to break it up because it's being re-computed frequently. It'll visualize that. But it'll be a separate DevTools thing. Got a separate extension. Thanks. Well, Dave, it was... Yeah, I feel so blessed having you here discussing, not face to face, but remotely about Recoil. Thank you so much for taking your time and showing the world what Recoil is about. Yeah, it's really cool to see that people are using it and interested. And I hope that we do get to meet in person sometime. Hopefully, yeah. Once the pandemic will... Go up to visit. Exactly. Thank you so much, Dave. All right. Yeah, thank you. Have a wonderful day.