What's new in React: Hooks and Suspense

Written by Edward Hewitt in Engineering on April 19,2019

A lot of developers choose React as a framework for their web applications. Most will need a Headless CMS (like Prismic) to be able to edit and publish new content.

This is the transcript of a discussion about two new React features: Hooks and Suspense. Wes Bos (Full Stack Developer, Speaker, Podcaster, and Teacher) and Sadek (Prismic's CEO) shared their thoughts on what they are and how they might drastically change application loader management and the developer experience.

Watch it, read it, or scan it - but if you're interested in React you should definitely take a look.

Highlights:

  • Hooks allow you to separate the component logic from the rendering in a React Component.
  • Suspense allow you to defer rendering part of your application tree until some condition is met. For example, to display a loader while doing asynchronous data fetching.

Sadek: I'm here at Prismic, and I'm glad to be here with Wes Bos. Wes, can you introduce a little bit yourself?

Wes: Sure, my name is Wes Bos. I am a Full Stack JavaScript developer, all the way from Canada. And, I make JavaScript courses in web development, and I have a podcast called Syntax.

Sadek: We were talking about two new things in React: Hooks and Suspense, that have been released, right?

Wes: So, Hooks is at the time of the recording, Hooks just got in last week. Suspense is still being worked, so some of this might change, but it should probably come out in maybe six months or so, from time of recording.

Sadek: Cool, and let's start with Hooks then. Right, can you explain what Hooks are? And why are they interesting?

Hooks solve the problem of being able to inject stateful logic and side effects into your component.

Wes: Hooks solve the problem of being able to inject stateful logic and side effects into your component. The way that we currently do it is: you have a class that extends the React.Component, inside of that class you generally have a render, which outputs your HTML, and then if you want data inside of that, you'll have state. And then, if you want to like, do things at different times of the life cycle of that, you've got ComponentWillMount(), ComponentDidUpdate(), and ComponentWillUnmount(). And in those three things, you generally inject logic as to things that need to happen at those life cycle methods,.

Sadek: And the problem with that, as you told me before is that people- everyone handles their own way, right? There's no one way of doing that.

Hooks aim to do is to take all that state and logic and everything, and move that into a separate function that you can easily use to inject data and functionality into your regular components.

Wes: Yeah, so the way that we solve that now is if you don't want to attach what it does with what it looks like (which is your render and your functionality). What we do now is that we use to have mix-ins, those are gone in React, and we have high-order components and that sorts of fell out of love in order of render props and that worked well but it's this like ugly arrow syntax, where you have four or five things you need inside of it, it's nested really deeply. So, what Hooks aim to do is to take all that state and logic and everything, and move that into a separate function that you can easily use to inject data and functionality into your regular components. So, we're going to just have your components now are just going to be functions. Classes aren't going anywhere, but you can just have a regular function that returns some JSX.

Sadek: Simple.

Wes: ...And if you wanna inject data, or functionality, or subscribe to a database, or anything else that's sort of like that, you create what's called a Hook, and then inside of the Hook is where you sort of tuck all of the logic and stuff into it, and then inside of your render function of your original component, you can access the data and the functionality

Sadek: And interact with it.

Wes: And interact with it, yeah.

Sadek: So, more concretely, how would the syntax look like?

Wes: So, the way that it works is, imagine that you have a function that returns some JSX. Before you do that return, you would say like, const, and let's say you state for example, if you wanna have age, you use an array, and the first thing in the array is going to be your piece of state, your variable that's updated,

Sadek: So that you can use it for the render again.

You run your state, you pass in your initial value, under the Hook that's all memorized, meaning that if the components were to be re-rendered, it doesn't start from scratch again

Wes: Exactly, so like const [age, updateAge] the second thing is an updater function, and then that is returned from a used state Hook. So you run your state, you pass in your initial value, under the Hook that's all memorized, meaning that if the components were to be re-rendered, it doesn't start from scratch again. It knows internally that, that thing has been run already, and that's cool because then, just below that, in your render, you then have access to this live variable called age, and you then have access to this updated function which we then can call anytime you want to update that value.

Sadek: Right, seems much simpler. But then, can you give us a concrete example of like maybe a shopping cart component? What are the things that you would use Hooks for in a cart?

Wes: Yeah, you've got a shopping cart component. Inside that, you might have some state, which is the things that are in your shopping cart. You might have some functions to remove items from your shopping cart, update the number of items in your shopping cart. And then, you might have some other side effects where maybe you're syncing that to that database, maybe you've got some other functions that would sync into some event reporting, maybe like, this user added to the cart-

Sadek: Marketing things

Wes: Yeah, marketing things. Everybody needs to hook into that. There you go, that's why it's called a hook! So, there's a lot going on there. And previously what you do is you stuff all those things in all of your life cycle methods. Even though they're not totally related, right? So, what we can do now, is you could use a Hook for your state, which is your items in your cart. You can use another Hook for all the functions and updating that. Or, you can create your own Hooks, which internally can have state and updater functions and all of your own custom logic, which is cool. And then, you can make just a separate Hook that's for marketing, called like "Used marketing Hooks" or something like that, and all that will do is just, you can just run those functions nice and tidily. I really like that! Because you can just like, tuck all the messiness of that functionality into its own Hook, and then just expose it via the Use Hook API inside your render.

Sadek: Especially, you can make, different Hooks, right? So you don't have to mix some marketing code, things that are turning-on things in marketing, with the functionality of synchronizing with a database.

Wes: Exactly.

Sadek: You can make different Hooks for that.

Wes: Yeah, exactly.

Sadek: So, it seems like maybe, React is finally being opinionated on something, right? It's like they're having an opinion and suggesting a way to fix this thing.

That's the thing about React, is they've been very un-opinionated about how to handle these things, and in high-order components, and render props have come out of, just like, us figuring out hacks we can do with functions.

Wes: Yeah, that's the thing about React, is they've been very un-opinionated about how to handle these things, and in high-order components, and render props have come out of, just like, us figuring out hacks we can do with functions. And it's really cool that they have now come out with a first-class API for doing this type of thing. And we can talk about that in Suspense as well.

Sadek: Yeah, so Suspense.

Wes: Yeah! Suspense is a new API that's coming to React. This might change, but previously dealing with data and asynchronous fetching (we say data, but it could be for fetching any sort of stuff behind any sort of asynchronous call as behind the scenes). The way that it's gonna work, and the problem that suspense will solve, is that where you fetch your data and where you want to maybe show like a loading indicator, is not necessarily always in the same place. So, we've all been to websites where you load it, and you see six or seven different loaders, really quickly because-

Sadek: Oh yeah, that's really ugly. I mean, and it's very hard to solve, when you see it on the website, you say, "why did they do it that way?" but it's extremely tricky to solve.

What Suspense will do is it will allow us to take our asynchronous calls, so whether that's fetching a bundle of code, whether that's fetching some data from the API, or whether that's loading an image, and we can turn those calls into what are called Resources.

Wes: Well, we just got done talking about componentizing and keeping the query with the component in this nice, tidy little package, and that sort of falls apart when you need to talk to the higher component and tell them like, "hey, I'm loading something", right? So, the solution is just to show a loading indicator where you're fetching the data. So, what Suspense will do is it will allow us to take our asynchronous calls, so whether that's fetching a bundle of code, whether that's fetching some data from the API, or whether that's loading an image, and we can turn those calls into what are called Resources. And then, kind of like how Hooks work, before you render, you can read a resource, and it looks like asynchronous function, where before the render happens, this read function from your resource will return the data to you. And a kinda cool little thing about that is you can also use a cache, meaning that you can preload them, or if you wanna render something twice, it's not gonna fetch the data twice. So it'll take care of the caching for you as well.

Sadek: So, it's pretty much about wrapping that call with another function, and then use that function instead, and then that's it. React knows about that's happening, and then you can use it at a higher level component that will be able to know about: "Okay, fetching is done, then I can stop the loading".

Wes: Yeah! So you forget about loading in your component altogether because you just read this resource and then it will render when the resources is read. And then, at a higher level, you can wrap it in a Suspense component, and that Suspense component you can dictate what will show when it's loading. So, if you've got like a user component that's fetching, and maybe a list of their GitHub projects. That's two requests. And you can wrap both of those in a suspense component that will maybe just show like a dummy component or show a loading indicator entirely, you don't have to show the entire user component at that time.

Sadek: Right.

Wes: Another cool thing it does is that you can specify the delay. So if you've been to a website and you have a fast connection, you might see six or seven loaders for 200 milliseconds, just really quick. And you can specify like, "alright, for the first 500 milliseconds, don't show anything, and if the resource is taking longer than that, then show a loader".

Sadek: But that, it will do it for all the components at a global level.

Wes: Yes, yeah.

Sadek: Yeah, and that's the coolest thing about it. You don't have to handle it at all at the level of the component, but then at a global level the loader will be able to wait enough and then start showing you the loading indicator because you need more time.

Wes: Yeah, you don't need to like dispatch all these loading events, catch them at a higher level, and then figure out six of the seven are finished loading, or whatever. You can just, wrap up a couple resources in a suspense tag and figure out what you want it to show at that point.

Sadek: Way simpler.

Wes: Yes, yeah, absolutely. I'm looking forward to it.

Sadek: Cool. Well, Wes, thank you very much for explaining this.

Wes: Absolutely, thanks for having me!

Sadek: Cool.

Edward Hewitt

Content Strategist. If the devs have their way, Edward will one day be replaced by a Prismic feature.