Check out a free preview of the full Complete Intro to React, v9 course
The "Class Components" Lesson is part of the full, Complete Intro to React, v9 course featured in this preview video. Here's what you'd learn in this lesson:
Brian spends a few minutes reviewing class components while introducing Error Boundaries. The ErrorBoundary can wrap around one or more components in the application and provide alternate content when an uncaught exception is emitted. Additional tips for working with class components are also shared in this lesson.
Transcript from the "Class Components" Lesson
[00:00:00]
>> Brian Holt: So we have been talking so far only about function components. That used to be a very interesting and distinct word in the React world, and we've moved so far towards function components that we don't even remember class components. However, they are still there, they're not deprecated, and there is one use case as far as I can tell where you can only do it with a class component and that is error boundaries.
[00:00:30]
So what happens if, let's say our past.lazy.jsx had an error with its API request and it was an uncaught error. It would just bubble up to the top of the app and crash the app, right? As you've seen several times happen in our app where it just says, I give up, the whole thing crashed, right?
[00:00:48]
There's a thing called error boundaries that allow you to catch those errors and prevent it from crashing your app, and you can only do it with class components. So I'm kind of taking this as a dual opportunity to teach you error boundaries, which frankly I don't really write too much myself because there is react-error-boundary, this component here.
[00:01:14]
Written by a member of the, I think he's an ex-member of the React Core team. I don't think Brian works there anymore but he used to. He made a component that just does this for you. So generally speaking I'm going to recommend that you just use this and not write them yourself unless you need to.
[00:01:30]
That's not gonna stop me from teaching you how to write it yourself, though, and the reason being is I want you to see a class component. Cuz if you are gonna hop into a company that's been writing React for a decade, you're definitely gonna see some class components laying around, cuz this used to be the only way to write React.
[00:01:47]
Function components are as a result of, I don't know, probably six years ago at this point where they were very first introduced, right? And over time they've become so popular and hooks made it so that you actually don't ever need class components ever anymore. Let's talk about class components.
[00:02:02]
Number one, no hooks, cannot use hooks with class components. Just kind of sear that in your brain because you're gonna be tempted to but you can't. So for example if you made a custom hook like use PizzaOfTheDay it is not usable with a class component. Now, you can kind of hack it, what you do is you make a function component, you run the hook, and then you pass it into a class component as a prop, right?
[00:02:32]
So you can kind of cheat a little bit, which you may need to, but inside of a class component, you can never use a hook.
>> Brian Holt: So there's no state, there's no useState, there's no useEffect, it has its own set of APIs for doing that.
>> Brian Holt: So let's just start writing one, I think that's probably kind of the easiest way to do it.
[00:02:53]
I want you to make a new file here, and it's gonna be called ErrorBoundary.jsx.
>> Brian Holt: Yeah, they're in this weird state where they're not recommended, but they're not deprecated. And I don't really understand that. Either just say we're gonna maintain both of them or say we're just deprecating one of them, right?
[00:03:23]
I don't know, but I'm not in charge, no one asked me. So we're gonna import { Component } from "react" and we're going to do this thing, say class ErrorBoundary extends Component. Somewhere in chat right now, there's a Java developer just getting really excited, just pumped about what we're doing here.
[00:03:50]
>> Student 1: [LAUGH]
>> Brian Holt: And everyone else is like, what is going on, right? And just down here at the bottom, we're gonna export default, ErrorBoundary;. I actually like class components, I don't write them anymore because no one does. But there actually used to be a React function cuz you do like React.createClass like this, and then you would give it an object, it would look a lot like this.
[00:04:19]
This was the original way of writing React years and years and years ago, if you look at Complete Intro to React, v2, right, it's all taught with createClass, this was my favorite API. Don't tell anyone that, this is just between you and me, but I really liked that and I kinda miss it.
[00:04:37]
That Wolverine meme of him stroking a picture, that's me and createClass. I do that with the docs [LAUGH]. All right, so state =, we we're gonna give it some amount of default state, and by default it has no error. By the way this is just a normal ES6 class, or ES2015 class.
[00:05:03]
So nothing special here, this is just React using JavaScript classes, okay? It's got a weird thing called a static method. Again, if you're a Java developer, you're just pumped about life, you're just ready to roll here. Everyone else is like, I don't understand, why are you writing Java in my JavaScript?
[00:05:27]
>> Brian Holt: A static method, so if you have a class here, you can say ErrorBoundary.getDerivedStateFrom and it works directly on the uninstantiated class, right? As opposed to everything else is an instant method, so you have to say const eb = new ErrorBoundary;. And then if we have something here like lol, right, then you can call eb.lol, right?
[00:05:59]
It happens on the thing that you nude up, whereas something that is static is called directly on the uninstantiated class. If you're looking at me like, I don't know or care about the difference, that`s acceptable, that's fine, [LAUGH] but I just wanted to tell you the difference of what static is, right?
[00:06:20]
The reason why they do this is because when it hits an error, it's gonna call this ErrorBoundary function so that it can get the proper state of it, because the thing is gonna be busted, right, because it caught an error. And so it has to kind of rebuild itself, and it does that with this getDerivedStateFromError, that's where it comes from.
[00:06:39]
So we're just gonna say whenever it gets busted, we just want to make sure that it has this state in here of hasError, we wanted that to be set to true, right? There is no lol function, by the way. So it's gonna go from having a state of hasError: false to having an error as true whenever it gets busted.
[00:07:03]
And then you're gonna run this function called componentDidCatch, it's gonna catch the error and info.
>> Brian Holt: And here, if you had something like send to TrackJS/Sentry, or something like that, you would send it off and log your errors here. I'm gonna show you this sophisticated technology of where I log all of my errors, which is console.
[00:07:29]
Console.error("ErrorBoundary caught some stupid error",) I like my tools to tell me that I'm dumb, it motivates me, error, info, okay? And then here's kind of the interesting thing, every component, so every React component, class component has a render function. Everything else is totally optional, but it must have a render function, and the render function is 95% the same thing as just a normal React component function body.
[00:08:12]
So here's where you're going to return something, so, if (this.state.hasError),
>> Brian Holt: Then you're gonna return your error, whatever you wanna show the user, right? So you're gonna say something like error-boundary
>> Brian Holt: <h2>Uh oh!</h2>, <p>, there was an error with this page. And then we'll pull in a link.
[00:08:56]
Make sure we import that as well from up at the top, import { Link } from '@tanstack/react-router'. We're gonna send this to just the homepage and, click here,
>> Brian Holt: To go back to the home page,
>> Brian Holt: Okay? All right, so if you have this ErrorBoundary wrapping your component, what do you want it to display if there is no error?
[00:09:38]
>> Brian Holt: You don't want it to add anything of itself, right? You just want it to just be a straight on invisible passthrough, right? So in that particular case, instead of this one, rather, you're gonna say return this.props.children;. It's not wrapping it or anything like that, it's just saying if I have an ErrorBoundary around MyComponent, or let's make it even simpler and just say that an <h1> of,
>> Brian Holt: Something like this, right?
[00:10:14]
If there's no error, be invisible, right? Don't show me anything right? And that's what this does, this is just saying, I'm an invisible path through, do nothing, and then if this, for whatever reason, has an error, right, then display this. Don't do anything with the children, right, just display this, and then that's how that works, right?
[00:10:36]
Okay, that's it for an ErrorBoundary, just a slight more on class components. I showed you one of these, they're called life cycle methods. So before we had effects, right, where you can kind of use effect to affect different parts of the component life cycle. This had very strict named parts of the life cycle, so you could do something like componentDidMount, right?
[00:11:03]
And this would be like, when we do use effect and give it an empty array so it only runs once, right? That's what componentDidMount does, right? Or componentWillUnmount, this is like that returned function from a use effect, right, it runs once at the end. Or if you wanted to do, where is component, there's componentShouldUpdate, not the one I'm looking for, componentDidUpdate, that's what I'm looking for.
[00:11:35]
This is an effect that's rendering again and again based on, remember we were looking pizza size, right, where we were having it run every time pizza size ran, right? componentDidUpdate runs every single time the component changes, that the state changes, right? The other thing I'll just mention kind of briefly, there's also a constructor, that's also something that you should know.
[00:12:01]
If you ever have to do something when the component is very first created, you have to put in a constructor and you have to pass this up to React. And the way you do that is you pass it to the super, the class that's above it, which is the component.
[00:12:18]
So you take the props in and you have to pass that to React, that's what this super(props) things does. Why I'm kind of grateful I don't have to teach this anymore is because you have to learn a lot about this. And if you've ever done a JavaScript interview, people love to talk about what this is, right?
[00:12:39]
And really, the big problem here is if I do something like, let's call this function, I don't know, celebrateError, okay, and I say this.setState.
>> Brian Holt: celebrateError, or something like that, celebration,
>> Brian Holt: Okay, and I wanna put this every time that you click on this, onClick =(this.celebrateError).
>> Brian Holt: This is not gonna work yet, which sucks, right, why?
[00:13:27]
Because, what is this here? Your answer that question should be, I don't know, Brian, why are you asking me this question, right? And the answer, I think it's undefined or something, right? Or window, but it's not what you would expect it to be. So, you have to go do something really silly like this.celebrateError = this.celebrateError.bind(this), and then this will actually bind the context so that this will be correct.
[00:13:57]
Or you can get extra silly and you can say celebrateError = function and you have to use an arrow function like this. Now, why does this work? It's because error functions, or arrow functions, have a different, context setting methodology than normal functions. Its lexical, I think is the term that they use for it, or it's the other way around, I can never keep them straight, but it's where it's written, not where it's called.
[00:14:29]
Whereas these functions, the context is set where it's invoked, not where it's created. Again, if you're looking at me like, am I speaking Chinese? I might be, I actually don't know, right [LAUGH]? But I'm just kind of trying to survey the land of where the landmines are here.
[00:14:47]
And so just be aware that you have to get kind of into the weeds of what this is. I asked you to also see here that I called this.setState, this is a React functionality for class components. This doesn't exist, obviously, on function components, but this is what it uses instead of useState, right?
[00:15:07]
You do this.setState, and then you change the state, and this will be a massive object of all of the state, right? As opposed to having a one hook for every single piece of state that you have, you got one big old object. And so, for example, right here you can see that I have hasError, that's some state on here.
[00:15:24]
This won't overwrite it because it does an object merge between the two, so just be aware of that.
>> Brian Holt: Last thing here is if you wanna reference the props here, you just say console.log(this.props.lol), whatever you would normally get props here, right? Instead, you just reference them here under this.props.
[00:15:50]
>> Brian Holt: Okay, that's kind of a whirlwind tour of class components, enough hopefully that you kind of get the lay of the land, that if you have to use them, you know where everything is. I've kinda shown you the 95% of them, beyond that, everything's kind of the same between class components and function components.
[00:16:10]
One more thing I was gonna show you, I kind of referenced it earlier, but let's say if we had to use our custom hook here. I would do something like function EBWithHooks and I would do something like const potd = usePizzaOfTheDay and then I would return (ErrorBoundary) with,
>> Brian Holt: Something like this, right?
[00:16:47]
So you do all of the hooks above it in a function component, and then you pass them down into the component that way.
>> Brian Holt: Kind of silly, but it does work, right? You can kind of use the tools and compose them together.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops