Epic Web Conf late-bird tickets are available now, hurry!

Get your tickets here

Join the community and network with other great web devs.

Time's up. The sale is over
Back to overview

Realigning Your Model of React After Hooks With Dan Abramov

Dan Abramov discusses how the addition of hooks changed how we write React.

In this episode, Kent and Dan talk about the ways in which you'll have to reconstruct your mental model of how React works in order to get the hang of hooks, and how hooks more closely align with React's intended model.

React has made multiple attempts at figuring out a way to share state between components. Mixins, higher-order components, render props, and now hooks. Dan Abramov walks through what went right and what went wrong with each of the implementations prior to hooks. None of these implementations lined up with React's model, they were too indirect, or too limiting.

Classes didn't properly fit in with React's component model either. Components don't use inheritance, they aren't ever instantiated, you don't call methods off of them. Dan explains how Components are more like a stateful function, and how Hooks are a closer approximation of this mental model.

Guests

Dan Abramov
Dan Abramov

Transcript

Kent C. Dodds: All right. Hey, everyone. This is your friend, Kent C. Dodds, and I am with my friend, and hopefully your friend too, Dan Abramov. Say hi, Dan.

Dan Abramov: Hey, there.

Kent C. Dodds: You're so enthusiastic, I love it. Hey, there. All right, so Dan, I am super excited to talk with you always, like any time. I really enjoy our conversations. Yeah, today I wanted to talk about ... Well, maybe it'd be good to give an introduction to you. I kind of take for granted that people will know who you are, but it'd be great if you could give us a little intro to yourself. Tell us who you are, what you're about, what you're doing, and maybe you could just say one non-tech thing that you're interested in?

Dan Abramov: Okay. Right, so my name is Dan Abramov. I work on the React Team on Facebook. React is a UI library, but if you're watching this, you probably already know that. One non-tech thing that I'm interested in? I haven't had any hobbies for a while. I think the only non-tech I'm doing lately is watching Netflix. I don't know if that counts, but ...

Kent C. Dodds: I've been there, for sure. Sometimes you're so into it.

Dan Abramov: I play Fortnite, but really badly.

Kent C. Dodds: Nice. Very, very cool. Cool. Today, Dan, I wanted to talk with you about Hooks, of course. That's kind of the thing that is on a lot of people's minds, whether they're into React or not. We have the people who are super interested in this new Hooks thing almost to a fault, and then I think maybe I lump myself in that category a little bit, but then we have people who are really skeptical of it, and like, "Oh, I guess you just must hate classes, and you want to make things complicated just to make things complicated. Whatever." So there's a lot to unpack here with Hooks. And I think there are a lot of really good resources for people getting started with Hooks, so I don't want to go too far into that. You know, Reactjs.org/hooks, and watch that video, and you'll get a really good intro the concept of Hooks. But yeah, why don't we kind of unpack the idea of ... Or maybe we could start with just a little brief why-Hooks thing, and then we can get into some more details there.

Dan Abramov: All right. Do we assume that people watching this already watched the video introduction, or do you want me to recap it?

Kent C. Dodds: You can give us a 20-30 second little intro to conceptually what Hooks is.

Dan Abramov: I think the way I think about Hooks is really two parts. One part is that we ... Hooks lets you reuse behavior between components more easily, in a very flexible way. Another part is, so in order to do that, we need to give you some [primitives 00:03:13] that you can ... Like, the building blocks that let you do that. The second part is that those building blocks turn out to be sufficient to implement pretty much all React features. In that sense, Hooks also lets you write code without declaring the component class, because it turns out that those building blocks that you used to build these reusable behaviors, they're also sufficient for just declaring components. You can think of Hooks as a new component API that is a little bit more flexible.

Kent C. Dodds: Cool, and I think from my takeaway, or my impression from the messaging that I've seen is the biggest motivation behind Hooks is a desire to have a simpler way to share logic between these components, like you said. Before, with classes, we had ... Well, with React.create class, we had [mixins 00:04:18], and those worked pretty well, but they had some problems. Also, I think the desire was JavaScript now has classes, let's not re-implement our own version of classes. So we move over to classes, and we lose mixins, and so then we started thinking, "Well, inheritance isn't the approach we want." So Sebastian came up with this idea, "Oh, this higher-order component, a function that makes a component that can be like a configurable component kind of thing." That had some problems, and we move over to render props, and [react-spring 00:04:48] or react-motion was a big initializer on the render props idea, and this headless UI concept. That was really good, it had a couple of little problems. For you, what was the big drive toward Hooks? What were the things that the community was kind of missing out on before Hooks came around?

Dan Abramov: I think it's kind of hard to explain, because all of those things kind of tie together. Every one of those patterns, I'm not saying that they're bad. Like even mixins are kind of okay-ish, but eventually you just run into walls with them. With mixins specifically, they suffer from the same problems as multiple inheritance, because they technically are multiple inheritance. Eventually, as you use them more and more, you're going to run into [naming 00:05:56] clashes. You might have two mixins, but you can't use them together, because maybe they both use some other mixin, but they want different things from it. They don't really compose well. The higher order component pattern, it solves the composition problem, so you don't get name clashes [in 00:06:23] methods, but then the problem ... So higher order components have a few problems. One of them is just the code becomes very indirect. I think that a big ... Like, we consider it kind of like a principle, or a value I guess for React, is that we prefer direct code. I guess we don't discourage it, but I think we prefer when it's possible to write code that you can read it, and you can understand what's going on without doing these mental gymnastics of like, this thing, it actually gets into this [inaudible 00:07:05] function, and then ... We want to see the connections between things. With higher order components ... Yeah, go ahead.

Kent C. Dodds: Oh, I was just going to add, that also is I think what makes higher order components really difficult to type with, [Flow type 00:07:23], or [TypeScript 00:07:24], is that layer of indirection, for sure.

Dan Abramov: Yeah, so that's another related problem, but even if just look at some prop, and they're like, "Where is this prop coming from?" Well, if it's just the regular React component, it comes from a private component. But maybe there's like five higher order components in the middle, and each of them passes something to the other one, and you don't see it unless you actually go into them. The whole dataflow becomes obscured, so that's one of the problems with higher order components. They also can have name clashes, not in the method names, but in prop names. That's also an issue, and method calls, you need to forward ... There are some [inaudible 00:08:09] cases, but anyway, render props solve some of those. With the render props, they seem to be closest to React. They don't suffer from a lot of those problems, because they kind of embracing rendering. React's components' life happens in the render method. That's really the [Reacty 00:08:35] part of it. The rest is just, "Yeah, fire this sometimes, fire this sometimes." But really, the big picture happens in the render method. And so the render prop's pattern is ... By putting more stuff into render, it benefits from this explicit dataflow, and explicit composition, and you can trace every value exactly where it's coming from. If you want something a few layers deeper, and then you have props a few layers above, you can just reference it, because it's in the [closure 00:09:06]. I think the render props are really helpful in that sense, but if you ever tried to use render props more widely than a few components, you're going to have this ... Just like callback [hells 00:09:23], or we call this [inaudible 00:09:24] hell, where there is a notion of tree structure, so you can have this locate, meta-query, location, watcher, and fetch, or something like that. So you have a pyramid of them, but conceptually, there is no clear hierarchy between them. So when we talk about the hierarchy of React components, we use it because they pass some values to each other, because they may have some local state, they may want to show its children, hide in its children, and stuff like this. But with a tree of render props, conceptually they're just a list. It's just a list of things you care about, and then you use them in rendering. [Dominick 00:10:13] had this idea about a custom syntax what would look kind of like [async/await 00:10:20], but it would instead [inaudible 00:10:24] these trees of render props into ... Like [inaudible 00:10:29] so that you can write them as plain function calls, and I think based on that, Sebastian came up with this idea of Hooks, which it's not using render props, but conceptually, it's like you use things in render by just calling functions, but those can have state and side effects encoded in them. So this allows to express the same patterns as render props, like 90% cases, where you don't actually want this nesting, but they're just as expressive. What's cool about it is Hooks are a bit more expressive than just render props. As an example, if you used render props, you've probably run into this a lot of times. Maybe you have a render prop, and it gives you some value. Then you're like, "Oh, actually, I need to use this value in the lifecycle method."

Kent C. Dodds: Yes, absolutely.

Dan Abramov: Good luck, you can't do that. You have to split the component in two.

Kent C. Dodds: No, you can't do it. Yep. Mm-hmm (affirmative).

Dan Abramov: Right. So with Hooks, you don't have this problem, because there is no false hierarchy. The whole thing happens in render, so you just get that value, it's in render, and then instead of lifecycles, and you have effects, which can reference values and renders. So it is just naturally there. There is no special API to read context in the lifecycle, or read some render pop in the lifecycle. Things can just refer to each other. I think that's the real benefit that I saw that sold me on Hooks is just that they express all of these patterns in a very straightforward way.

Kent C. Dodds: Yeah, I love it. I think we're always in ... Probably coding in general, we're always trying to find better ways to share logic in a way that doesn't leave us with code that's hard to maintain. I feel like every step of the way, we got a little bit closer to that. It's cool to think, or to realize that Hooks kind of came from this idea of that special syntax for adopting ... It was adopt keyword, right?

Dan Abramov: Yeah.

Kent C. Dodds: And that was the idea, to adopt these render props, and where we can take the cool patterns that we have to share this logic, and make it even cooler by just having it more expressive. With each one of these transitions to these different patterns, and these ideas, or even APIs, we've solved some problems, but then brought up some new ones. I feel like there are ... Like for Hooks, one of the things I was excited about as an instructor was to never have to worry about teaching people anything about this anymore in JavaScript, where this needs to be [pre-bound 00:13:35] and so you're using this ... Well, it's standard now syntax, and this kind of thing. But then when do I use a method, and when do I use a bound method? And all of that. Now I don't have to teach that, and so I'm pretty happy about that. I feel like that was kind of an annoying thing for people to come up against. But now, I feel like we're exchanging some of those challenges for some new ones potentially. What are some of the challenges that you see people facing when they're trying to wrap their heads around this new Hooks thing? And is there maybe room for improvements in this area, as well?

Dan Abramov: I think the biggest one that I'm seeing is just ... Like, especially if you already come from ... Like, if you already used [inaudible 00:14:36] some React, or you used another library that kind of looks like React, you might have an existing mental model of how lifecycles work, when is render called. I think that if you come with that perspective, when I look at code using Hooks, you might have two kinds of problems. One kind of problem is when you just don't get what's going on, you're just confused. But another more subtle problem is when you just apply your mental model, like from classes, and kind of make a one-to-one mapping to each concept. Like use effect is just lifecycle, or this thing is just that thing. Then when this mental model doesn't quite match, because conceptually it is a little bit different. I think if you don't internalize this difference, and like if you don't realize that you need to think in Hooks, you need to unlearn what you knew before, and try to think about it in a different way, I think that can be challenging. However, I am not too worried, because looking at the beginners, and people who don't have experience with class React, I find that they catch on to using Hooks way faster. It's mostly the existing habits, and existing mental models that can be hard to break. But another thing that comes up is that people say, "Oh, this is not intuitive. Class lifecycles were way more intuitive." I can see where they're coming from, and in some cases, I agree that it might be more obvious how to use a specific class lifecycle in this specific situation, but also I've been here for a while. I've been on React [inaudible 00:16:46] since 2014, and I remember people getting wildly confused about the class lifecycle methods, and they didn't know where to put the data fetch, and should they [ever 00:17:02] do it on [componentDidMount 00:17:03], or [componentDidUpdate 00:17:04], [componentWillMount 00:17:06]. There's so many methods, which one do you pick? I think it took a few years before it kind of ... And like rendering also, people would create dominoes in render. People would be super annoyed that, "Well, why can't I just [jQuery addClass 00:17:23]? Why do I have to setState in order to toggle a class? This is ridiculous." I think it took a few years for this paradigm of UI driven by props and states to kind of propagate into the mainstream, and be adopted by other libraries and frameworks. The idea of top-down dataflow, and pure or [inaudible 00:17:54] render method, and I think that's ... Like, what I see around Hooks is, it looks a lot like Reaction 2014, where nobody really knew how to do ... Like, I'm still figuring out how to do some tasks, because it's just a different mental model, and sometimes I look at the code, and I'm like, "Wait, I'm not sure how to translate it." And then you just spend some time, and then you're like, "Oh, okay. This makes sense." The next time you see this problem, I'm like, "Yeah, we solved this before." And this is the exact process I went through in 2014 with class lifecycles. But I guess the takeaway for me here is that if you're not comfortable figuring things out, then it might be a bit of an early time to adopt Hooks, because there are no best practices yet. This is a bit of a wild west, because we're all experimenting. And like at Facebook, we're still figuring out how to solve certain things, and it'll take some time, but I think the paradigm itself is solid, and it's just that we're still kind of figuring out the consequences of the paradigm.

Kent C. Dodds: Mm-hmm (affirmative). I like what you've said really well. I think it seems to me like more ... It's less what's intuitive, and more we were used to doing things a certain way, and now somebody moved my cheese. Now things are different, and I'm trying to map what I did before to this new thing. I used to just use show and hide with jQuery. Now I have to do the set thing, and so therefore it is not intuitive.

Dan Abramov: Yeah, and lifecycles in effect, it's like a direct analogy. You used to do [addClass 00:19:45] whenever you want, and now you have to setState, and that confused lot of people back then. But now, [inaudible 00:19:53], like I used to do fetch in componentAddMount whenever I want, and now I have to have an effect with dependencies that is driven by state. Wait. Why don't I just fire [it 00:20:07] off on mount? Why don't we have like [useOnMount 00:20:09]? Or like [useOnUpdate 00:20:09]? This is a very similar problem, because what React did in 2014 was it introduced this top-down dataflow into rendering, and so with Hooks, the same concept gets introduced into effects.

Kent C. Dodds: Mm-hmm (affirmative).

Dan Abramov: But people are not yet used to thinking of dataflow, and how that influences effects. They're used to doing one-off operations that are ... And so the problem with those is that, just like with addClass, your rendering output would often be inconsistent, because it's just like [inaudible 00:20:47] accumulates over time. If you forget to do it in some cases, your CSS class is going to be wrong, and it is going to look wrong. So the same problem happens in class lifecycles, where you might do fetch in componentDidMount, but a lot of people don't know that you're supposed to also do it in componentDidUpdate. But then you also need to handle [race 00:21:06] conditions, and make sure that if requests arrive out of order, then it still works. So there are a lot of gotchas with how you do it in classes, but many people just don't think about, and then they have bugs and then they figure it out. And with effects, they force you to confront that ... Hey, there is top-down dataflow, and here it's like, what do you want to do? And how does that thing feed into this thing? Sometimes you have to write a bit more code, and some patterns that are inconsistent, they will just like ... In React rendering, if you want to render different things on mount and updates, it's more code than if you always render the same thing depending on the state. It takes some adjustment, but the goal is to make rendering more predictable, and to make the side effects from the component more predictable.

Kent C. Dodds: Yeah, I love that. You know, one thing that I had to change about my mental model was on click handlers. Typically, that's when I would go do the fetch call, or that's where I'd set it in local storage, whatever the case may be. I've found that with Hooks, it actually makes more sense to just call a state updater method, and setState for this thing, and have it re-render, and have an effect do that. That has the really nice side effect, no pun intended, of making it so I don't forget to run that side effect when that state would change in other places.

Dan Abramov: Yeah.

Kent C. Dodds: In the jQuery days, you'd say, "Oh, I have to hide it here, but then there's this other case where I'm setting that state somewhere else, and I have to hide it here or over there." With React components, you've have something in componentDidMount and that'd be all the logic there, and then you realize, "Oh, I need to do that also if they click this button, so we're going to put that into another method, and we'll just call that in all these different places." But in reality, you pretty much always want those things to happen when certain elements of state changes, or whatever, and so you've put it into an effect, and it becomes a lot simpler in my mind to do things that way. So I feel like the cool thing about Hooks is not only does it give us this great way of sharing logic, which is probably the biggest thing that I'm excited about, but it also gives us a new way to think about interacting with the React APIs in a way that's a lot more expressive.

Dan Abramov: Yeah, I think it's just ... I mean, I don't disagree that in some cases, it can be more difficult. If you intentionally want a different behavior that is not consistent for some reason, between [inaudible 00:23:49] and updates, you have to write a bit more code. It kind of forces you to really kind of model the dataflow, which I think would even be worrying to me. That's something we've tried to avoid in React in general. We don't really want ... You know there are libraries where you have to learn 20 different API signatures in order to do even simple things? And you need to know how to compose them together, combine them together, and which one of them to use in which situation. That's a trade-off, it's like, you have it like this [inaudible 00:24:35] of different things, and you become a master at them, but this is not something that we generally want in React. We try to avoid this upfront cost of getting something right. So I think with effects, it could be a bit worrying that we are kind of forcing you to write correct code earlier, but you struggle doing that, whereas like you could've just wrote something that works half of the time, but at least it can [inaudible 00:25:10], and you can ship the next feature, and eventually you'll fix the bugs. So that could be a concern. The reason I'm not too concerned about it is custom Hooks. When you get it right, if useEffect was the only primitive available to you, and you had to use it directly everywhere, I think that would not be worth it. But the point is that once you get it right, you can actually put it into a custom hook, and then this custom hook has a simple API. For you, it could be just fetch, or use this thing from your application that used [inaudible 00:25:49] caller, and you don't really go there again unless it breaks. So the resilience, and the correctness afforded by getting it right when you write this useEffect, then it becomes this foundational stone upon which all of your custom Hooks are built, and then you know that those work consistently. It takes some effort to write them, but then you don't write a new one every day. You just reuse the ones that already exist. I think that's one of the reasons people are a bit confused right now, because we're just used to putting stuff into classes. So like similarly, whenever we want to do some lifecycle, even if we do that in all classes, like if [crosstalk 00:26:37] just copy-paste the same code, with Hooks, I think it's important to know you can extract things, and extract common patterns, and use them all across your app. It's totally expected that your app would have its own set of custom Hooks, and then eventually you wouldn't write useEffect every day. You would just reuse those ones.

Kent C. Dodds: Yeah, and that's one of the things I love about it. With classes, we talk about the separation of concerns, and you can have multiple concerns in a single component. You know, my concern is update the document title, my concern is subscribe to Firebase, but I'm putting them all in one component. And then I decide, you know, I want to separate these out, and the story for doing that between classes and hooks is wildly different, where with classes, I have to inspect six different methods, and lifecycle Hooks, and then put that in some sort of render prop thing. Where with Hooks, I just literally select all the text that I want, and if I'm removing it, I just delete it. If I'm moving it somewhere else, I just copy or cut and paste. That one element alone is just so valuable, and just lends itself to easier maintainability. We're kind of coming down on our time a little bit, Dan, but I want to ask you a question that maybe you can give us some insight into the React team a little bit. What's the deal? Do you just really hate classes? Is that why you went through all of this effort to just ... "Man, classes are the worst." Because classes, they seemed all right. We mentioned a couple problems, but I think I've seen a lot of people just say, "Oh, React folks just hate classes. That's why they went through all this trouble."

Dan Abramov: Yeah. I think we may have overemphasized ... Like, we have this like, "Classes are confusing," header in the docs, and I think we, like a lot of people, get fixated on that part, and maybe we overemphasize it in our message [inaudible 00:28:49]. The previous headers were kind of more important, and it's just this was the last one that we put in, because we wanted to show that we don't only care about existent users, but also about new users. It's a fact. If you try to train new people to React, a lot of them get confused by classes, and the thing is, it's fine. It's not that we're being anti-intellectual, or I don't know, we want people who don't any JavaScript to be productive in React. That's not really [feasible 00:29:26], it's just that we ... Speaking of learning specifically, we see that the struggles with classes have nothing to do with React itself. We would rather people struggle with things that are related to learning React, and to React mental model, and to how you design and write your components, but the technical issues that people run into with classes have nothing to do with React. It just seems like such a waste of time. But then again, this is not the reason Hooks don't these classes. It's just kind of a nice side effect that we no longer have to go through this. But for people who think that we hate classes, I think it's worth taking a step back and kind of ... If you look at the major UI libraries who adopted React classes, I think React was actually maybe the first major UI library that adopted JavaScript classes, and added support for playing JavaScript classes. Which is like, I'm not saying that it was the only one who was working on it, but I think it's the first one that's a major one, that supported them as part of public API. It was before [Bubble 00:30:52], as far as I remember. I think Facebook at the time used [JSTransform 00:30:56], which was like ... I think given even [inaudible 00:31:00] wasn't quite finalized yet, but react jumped on the classes train as soon as we could, because we already had our own create class implementation, and we just wanted to use something more standard. That the [tooling 00:31:15] would be build around it, or that the ecosystem converge around it, so that was the moderation. But we always had this ... So there is this repository, which is actually now outdated, it's called [React Feature 00:31:32], but it's not really future [crosstalk 00:31:34].

Kent C. Dodds: Kind of like React Future in the past?

Dan Abramov: In the past, yeah. It has some sketches of possible functional APIs. I think the last commit was like three years ago, four years ago on those sketches. We've always been thinking about that class is not exact ... Classes don't model React very accurately, and you might discover that even if you look at the recommendations ... So we say, "Okay, you declare a component with a class, or sometimes with a function. Like, [inaudible 00:32:14]? Okay, maybe because this one has state," but then you're not supposed to use inheritance. But isn't that what people use classes for? And also, you never ... If this is a class, why do you never instantiate it? Aren't you supposed to [new 00:32:33] a class? Why do you not pass it around? So classes give you objects, and then you pass them around, and you call methods on them. A big feature of classes is that you have this dynamic dispatch, so I can say like [something.sayHi 00:32:49], and then it has different implementations depending on the class. But that's not how you use React. You don't pass classes around, it's a very rare [inaudible 00:33:01] case that you would pass this around, but usually you just call this.something. So we don't even use dynamic dispatch much, and there are all these weird quirks of how ... Like this.props, like you're not supposed to put the fields onto a class for a state. You're supposed to state into state, and you don't even assign a state field. You call a separate method, it doesn't even update that field immediately, and then something else sets the properties on your class, that are special. You're supposed to treat those properties as function arguments conceptually, and some of your methods are supposed to be pure, even though they are class methods. It's like all of those things kind of point a mismatch between the React mental model, which is there are just components, and then the JavaScript reality, which is there are classes and there are functions. So we were experimenting with functional APIs, but none of them seemed to actually solve any issues that we cared about enough. It never justified the transition, but with Hooks, the combination of being able to express all these values, like being able to express all these patterns for code-sharing that custom Hooks enabled, and the flexibility that they allow with ... Like, you can call the same hook multiple times and it has isolated states in effect, and you can pass values between them, and they're all in the same scope. We think that this maps very closely to the concept of what a React component is. It's really a [stable 00:34:46] function and [effective 00:34:49] function, which is something you don't have in JavaScript, but there are languages that can allow it. So there is [F 00:34:54] and [Koka 00:34:54], which let you model this with language features. We think that this is what a React component is, and Hooks are just a closer approximation of that mental model in JavaScript than classes, which is why we want to use Hooks for components. But we're not like against [classes 00:35:13] per se. In fact, because I sometimes mix classes with Hooks. It's like, I write a component with Hooks, but then I get a [ref 00:35:21] to a class with some imperative logic, because imperative logic is often more convenient to write in a class, but it's not like I just extracted that or with the component, because it's not really technically like a part of the rendering. So yeah, we don't hate classes. We just think they don't quite match what a component is.

Kent C. Dodds: Yeah, I think that makes a lot of sense to me, and hopefully over time, that closer approximation becomes more evident for people, as especially new people get into things. I did recently teach a big group of like 60 engineers Hooks and React for the first time. I went through the whole, "This is what JSX is," and everything. It was really ... They were able to pick up on React use state really easily. Where they really struggled most was I had to walk them through what happens across renders, because like, "Okay, so I get this state, and I understand that's not been initialized yet, but then how does it call that function again? And then where is it going to get the state?" And they really wanted to understand "Hooks are arrays" kind of concept. And why do we have these rules? And then in particular, closures and understanding that the variables that the closure is using are going to exist at the time the closure was created. Those kinds of things were a bit of a struggle for them, too. But I think they got it. They told me they did, so what are some of the foundational elements of JavaScript that people really need to internalize so that they can use these new APIs effectively?

Dan Abramov: I think the biggest one is just being comfortable with closures. A lot of people see it, "Oh, this is super difficulty. This is ... I don't know. Closures, full of pitfalls, you have to Google interview questions about closures." Stuff like that. That's not what I mean by closures. I think in React's context, closures are actually way simpler. The reason for that is that ... There are two reasons. One reason is when people talk about closures being confusing, they usually actually talk about mutation. If you know this classical example of a for loop with a variable that is [var i 00:38:04] before [inaudible 00:38:05] [const 00:38:05], and then inside of a for loop, you have [setTimeout 00:38:09], and then you lock the value of that variable. That's a classical JavaScript gotcha, that like everybody ... Like there's, I don't know, 5,000 Stack Overflow votes question about it probably, but that's a classical gotcha. That you run this code, you expect to see like 0-1-2-3-4, but you actually see like 4-4-4-4 just because it's already been mutated, and the closure sees the last value. That confuses a lot of people, and that's why people are kind of scared of closures. But what's interesting in React's case, is that you don't really mutate things. You can, but it's not idiomatic. And so if we remembered with props and state themselves are actually immutable, so they can't change. They're basically inside of your render function, props and state are as good as constants. If you want to change them, you call as a state, that's going to trigger another render, and then in that render they're going to be new. But this render, they are constants. So when I look at props inside of a like [handle 00:39:24] something, maybe you have like [inaudible 00:39:25] or whatever, this props object that the close over is actually the same exact thing that was passed to you. It's not it's not going to change under you, like your trees is not going to move. So I think thinking about it this way actually, like closures just makes sense, because if they don't change, then they're as good as constants, and I think constants are pretty easy to think about.

Kent C. Dodds: Mm-hmm (affirmative).

Dan Abramov: It's just you need to kind of internalize this, that they're not going to change under you. But there's another reason which I think why this is not really a problem. It's that if you don't know that, and you use classes, you're going to run into a box caused by reading like this.props or this.state in some async callback, but those have already changed, because maybe you move to a different page. It's like if you follow a user, and then eventually you read this.prompts.user, but maybe you navigate to another page while we were doing that. So you don't want to follow the wrong user because of it. So the solution to that is a closure. Even if you use classes, you have to learn closures in order to solve this box.

Kent C. Dodds: Mm-hmm (affirmative).

Dan Abramov: So it's not like you could avoid them before. It's just you probably didn't like ... You might not have thought of it as a bug caused by mutation, because in this case React will mutate this.state, and this.props. So you don't think that you're solving it with a closure, but that's what we did, and I think we're just given ... Matching those concepts to their actual names in JavaScript, and I think it can be a bit disorienting if you haven't thought about this way before, but I think that it makes sense.

Kent C. Dodds: Yeah. You actually tweeted out a demo, a code sandbox for that specific example, right?

Dan Abramov: Yeah, so I tweeted an example of ... I think tweeted the example of a class component, and asked how you would convert it to a function, and like ... Oh, no. I made an example of function component, and [inaudible 00:41:35] how would you convert to a class? And everybody did ... Out of like 30 or 40 replies, I think only two were correct, because they didn't add a bug into the clause. But most class examples were buggy, because people didn't realize that they needed a closure to fix it.

Kent C. Dodds: Mm-hmm (affirmative), yeah. Let's see if we can find that, so we include that in the [crosstalk 00:42:03]-

Dan Abramov: Well, I deleted the tweet, because-

Kent C. Dodds: Because you got too many replies?

Dan Abramov: Yeah, and I was just preparing a blog post. The blog post is called ... It's on my blog. Oh, I'm actually going to plug it here now.

Kent C. Dodds: No, yeah.

Dan Abramov: It's on my blog, Overreacted.io, and I think that post is called, "How is function components different from classes?" And so that was just research for ... I wanted to make sure that people actually get confused about it, and they were getting confused about it, and then I deleted the tweet, because the two people who actually figured it out started posting answers, and I didn't want to spoil it for the blog post. So go ahead and read the blog post. You might find it interesting, and it's not really about Hooks. It's like, this is how functions worked in JavaScript. They always worked like this.

Kent C. Dodds: Cool. Well, Dan, this has been a super enlightening chat. I definitely want to talk with you a little bit more about the future of React, and where React is headed. We'll do that in another episode. Before we end this, is there anything in particular that you want to mention to our listeners?

Dan Abramov: I don't know. I hope you kind of like React, or not dislike it too much. I hope you're not forced to use it. If you are, I'm sorry. But also, yeah, I just wanted to mention that it's an early time for Hooks, and we're still figuring out how to do things with them. If you're kind of an early ... I don't know. If you're the kind of person like I was in 2014, who just wanted to play with something, wanted to figure out how it works, I wanted to figure out the patterns, I think I would appreciate if you tried Hooks, and if you tried to make something interesting with them. Give us feedback, raise an issue if something is not clear, we'll try to help you. But on the other hand, if you prefer when there are best practices, and when every question has an obvious answer, and when there are tutorials and articles that completely describe something, it might be better to wait out a little bit, and wait for those best practices to actually emerge. Don't rush into rewriting anything. Just give it some time to shake out ,unless you want to help. If you want to help then that would be cool.

Kent C. Dodds: Yeah, yeah. Absolutely. I think that's really great advice. It's fun to try these new things, but acknowledge the fact that when you're using something new, you're gonna make all your mistakes at the beginning. So I probably wouldn't rewrite your checkout button in your first try with Hooks.

Dan Abramov: Unless it has a bug caused by class, then sure.

Kent C. Dodds: True, true. Just make sure you're writing tests. Cool. All right, so that's it for today, or for this episode. Thanks so much, Dan. I really appreciate you taking the time to chat with us about Hooks. I think this will be helpful to people, so thank you.

Dan Abramov: Thank you.

Kent C. Dodds: All right, see you later, everybody!

Sweet episode right?

You will love this one too.

See all episodes

Featured episode

Become Intentional With Your Time With Scott Hanselman

Season 1 Episode 11 — 31:47
Scott Hanselman