Check out a free preview of the full Complete Intro to React, v9 course

The "useContext Hook" 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 introduces the useContext hook, which provides an API for managing state between components. A CartContext is created so the Header and Order components can access the cart state.

Preview
Close

Transcript from the "useContext Hook" Lesson

[00:00:00]
>> Brian Holt: Context, I teach this intentionally pretty late in the course, or in terms of, late of the fundamentals of React. It's a powerful tool. And I see new React developers get tempted to use it all over the place, because it simplifies the writing part of React. And I will say it greatly complicates the maintenance part of React.

[00:00:26]
This is another way of me begging you as your perhaps future coworkers, you'd be very sparing with your use of context. With great power comes great responsibility, I think I'm the first person to ever say that. [LAUGH] No, it's just props come from parent to child, and it becomes very explicit, the data flow of your app.

[00:00:50]
Context is being able to dump data into a portal and then somewhere else being able to receive data out of the portal. And so if you have five components that are passing data from parent to child, it can get a little annoying. That problem is called the prop drilling problem.

[00:01:10]
It's tempting to use context there, right? I'm gonna say, unless you're using that context in multiple places, that state in multiple different places, just deal with the prop drilling. I know it's annoying, but it is helpful. But there are some things that are legitimately what I would call app level state.

[00:01:35]
A really good example, this would be like a user, right? So if someone logs into your website, that doesn't just affect one part of your website, it affects everything in your website, right? You're showing the user their information, their checkout information, their address, right? And that's all pulling from the same piece of user information.

[00:01:53]
So you could have App.jsx, have useState user, right? And then pass that into everything. That doesn't seem like a good idea to me, right? I think it's better to say hey, we have this app level state that is the user, and then anyone can pull out of the context who the user is.

[00:02:13]
Does that make sense? So you're looking for what I call app level state as opposed to view level state or localized state, that's where context is useful. Theme is another one that will sometimes come up, right? If someone switches their theme that affects not just one piece of your code, it affects a lot of the pieces of your code.

[00:02:33]
So you might use theme as another piece of context.
>> Brian Holt: A lot of time libraries, so React router or tan stack router, which we're gonna look at here in a little bit. Those will use context quite a bit, it's also made for those things. And you don't have to care about those things because that's their problem not yours.

[00:02:52]
So in our app here, we have a header. And I wanna put a little indicator there of what's in your cart. And then the other thing that you can say about carts being as a function of context is, if someone navigates away from this order page. So let's say there was an about page or a contact page, which we'll build here in just a second.

[00:03:17]
If they navigated to the contact page, and then they navigated back to the order page, what would happen to the cart?
>> Brian Holt: Disappear, right? Why? If this gets unmounted, all of its state goes away, right? It doesn't get saved if it gets removed from the DOM, right? So if I come over here to App.jsx, we can literally do this, we're gonna add a bunch of stuff right here.

[00:03:44]
I'm just gonna remove this, okay? So I just removed it from the DOM, which would be the same thing from unrendering it, right? And then I'm gonna add it back. Notice that the cart is empty again, right? Because it got totally thrown away. It would be the same thing if you routed to a different page and came back.

[00:04:02]
Now again, we are in the business of making pizza money, right? [LAUGH] So, we wanna keep that cart full, right? Always be keeping cart fulls, that's what they say, right? I think so. [LAUGH] So, we wanna preserve the cart between page loads, at this point, what I'm getting at.

[00:04:20]
So we're gonna use context to do that. Now, really, what you could do, which would be probably a much simpler model of doing this, is you would just say, useState cart right there, right, and just pass it into all of them. But we wanna learn about context, I'm gonna show you how to do it with context.

[00:04:38]
So first thing, let's build the header that's going to read from the cart, okay? So new page we're gonna make it called Header.jsx. We're gonna say export default function Header(), okay? Return, and we're gonna put a <nav> cuz we all like semantic markup. Remember when that used to be a really big thing, and people would get all bent out of shape about semantic markup?

[00:05:11]
No, don't use divs, always use navs. What happened to those arguments? I feel like we should argue more about that.
>> Brian Holt: Padre Gino's Pizza, cool, and then we're gonna say div className = "nav- cart". And then I'm gonna put an emoji in here of a cart.
>> Brian Holt: Span className = "nav-cart-number".

[00:05:49]
Put any number you want in here, I'm just gonna put 5. And cool, that will be enough for now for our Header. Let's put that into App.jsx. I think we can just replace, so we're gonna import Header from Header, and I think we can just replace this. Yep, Header.

[00:06:15]
>> Brian Holt: You'll see that this is kind of turning out to be just a composition of a lot of other functions that we've made, or a lot of other components. It's kind of what React is, for the most part, it's just composing components and other components. All right, so now we got this like a little fun cart thing up there, right?

[00:06:31]
Obviously, 5 is fake, right? This isn't actually reading from the real cart. So how would we do that? Well, think about this for a second now, how would you do that right now, not having learned about context yet, how would you do it? There's no cart in here, right?

[00:06:49]
So you would have to do useState here, and you'd have to say, cart = (cart), and you would have to say, cart = (cart) here, but then we would have to actually pass in setCart here, right? Because then you end up with a bunch of fallout effects of that.

[00:07:07]
Well, nobody wants to do that, right? So, let's go ahead and do it differently with these contexts.
>> Brian Holt: So I've seen people do this with a bunch of different patterns. I saw one recently that I kinda like, so I'm gonna teach that one today. They just created a file called contexts.jsx, and they throw all of their context into one context file.

[00:07:30]
Thought that was kinda cool because it's never very much. My Context files used to be literally one line and then I would export it and it was just very short and sweet, but more short and dumb. We're gonna say createContext, which is gonna come from React, okay, and then we're gonna export const, so this one, you actually wanna do a name.

[00:07:59]
If you're gonna do this pattern where you have multiple different contexts coming from one file, it's important that you would do named exports, right?
>> Brian Holt: Export const CartContext = createContext(). You can leave it like this if you want to, and just call good there, for the sake of maybe your future TypeScript self and/or future testing self.

[00:08:31]
It is useful with context to give it, this is the shape of what is going to be held inside of this context. So we're gonna hold a hook in here, right? That's what we're gonna do, cuz we're gonna hold the state that's both mutable and readable. So what is the return type for a hook?

[00:08:54]
>> Brian Holt: It's an array. And what is cart? An array.
>> Brian Holt: And then what is this? Sum function.
>> Brian Holt: Right? That's what a hook looks like, right? So I'm literally just gonna put that right here.
>> Brian Holt: So, I show that too cuz I know this looks obtuse and weird, but that's why you're doing it.

[00:09:32]
Why this is nice? As soon as you pop this into TypeScript, TypeScript will be like, okay, I got this. This is an array with this, and it's just gonna check it and get it right away. So it's just a good habit to get into.
>> Brian Holt: And even though we're not using TypeScript anywhere in this project, VS Code does an okay job of observing types in here.

[00:09:58]
>> Brian Holt: Okay, so let's go set up our context, go to App.jsx, we're going to import {CartContext} from "./contexts". And the first thing we're gonna do is we're gonna wrap our app in this thing called CartContext.Provider,
>> Brian Holt: Usually strict mode is always gonna be the outermost thing. The order inside of it really usually doesn't make a difference.

[00:10:36]
So what is CartContext.Provider doing for us? Well, the first thing is that can be kind of strange with React, you can have components that don't actually render real markup. All they do is they act as kind of a pass through, but they augment the ability of the components inside of them.

[00:10:50]
And that's what this provider is doing. It's now making whatever value that we're gonna pass into it, which we'll do momentarily, we have not done yet. And it's gonna make that available everywhere inside of it. Now, what's kind of cool about this is, we're wrapping our whole app in it, but we could do something like this, where now only pizza of the day has access to this context.

[00:11:14]
Kinda cool, right? We could even have two different context providers and have each one of them wrapped in it. That seems like a weird idea, and I'm not super into that one, but you could do it. You can even have multiple cart contexts kind of layer out from each other.

[00:11:33]
And what it's gonna do is it's gonna find the nearest one, right? So it's gonna find the one that's closest to it. So if I had this, and then this, this is totally, I think it's value, yeah, okay.
>> Brian Holt: If I tried to access the context from PizzaOfTheDay, what value would it get back?

[00:11:55]
>> Speaker 2: 1.
>> Brian Holt: 1, now, again, you might be thinking, well, why would I do this? And I'm also asking you, why would you do that? [LAUGH] I don't know why you would do that. But it is possible, and it's why they had this kind of weird API.
>> Brian Holt: Okay, so going back to where we were, we're gonna say CartContext.Provider, a small footnote here.

[00:12:22]
They're making it so in React 19, you can just say CartContext like that, and leave off the provider, it's kind of nice.
>> Brian Holt: So if you're watching this with React 19, just go ahead and drop the .Provider. Now we wanna hook that we wanna pass into the context, so what we can do is we can say const cartHook =, notice we're not destructuring, useState like that.

[00:12:55]
And then the value here = cartHook,
>> Brian Holt: Okay?
>> Brian Holt: Remember, normally you would say cart, setCart and use that kind of destructuring here. Here we're passing the whole thing in.
>> Speaker 3: Does that mean that there's a setter that's also been assigned within the cartHook object?
>> Brian Holt: You got it, so now we can call that within order, cuz we need to, right?

[00:13:28]
We have to be able to set that hook from inside order, or else this whole kind of thing falls apart. Now, you might be thinking yourselves, well, does that mean you can set that hook anywhere? And yes, you can, and yes it is a foot gun, which is why I'm just kind of trying to steer you away from context as much as possible.

[00:13:46]
But there you go.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now