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

The "Context Q&A" Lesson is part of the full, Complete Intro to React, v8 course featured in this preview video. Here's what you'd learn in this lesson:

Brian answers student questions regarding if the context is read-only for the child components, if the context should be separated into smaller contexts or kept as one large context shared throughout the app, and where setAdoptedPet is coming from.


Transcript from the "Context Q&A" Lesson

>> Yeah, question.
>> Is the context read-only for the child components like props?
>> It's not, no, it's not read-only. So notice in here I'm passing the whole hook, right? Normally it'd be adoptedPet and setAdoptedPet, right? Because that's how hooks work. I am passing the holding hook in there, right?

Which means that both of these now have access to the value and the method to update the value. So it is a read and write, though the context provider doesn't care. Now, it is read-only in the sense of I can't just say like Provider.value = blah, right? It's always going to be whatever this hook is.

But the reason why I'm passing the whole hook into it is so that I'll have that setAdoptedPet value, which we're gonna call from details. So speaking of which, let's go to Details.jsx. At the top, we are going to import as well from react, we're gonna say useContext. From react-router-dom, we're gonna get useNavigate, And then we're also going to import, AdoptedPetContext from AdoptedPetContext, great.

Okay, up here, we're gonna say const, _, let's do this first. const navigate = useNavigate, this is a function that we're getting from react-router-dom. navigate is just a function to programmatically reroute someone somewhere, right? So we're gonna call navigate to route someone back to the homepage, right? So if you click yes, I wanna adopt Luna, it's gonna take you back to the homepage.

navigate is the function that's going to allow you to do that programmatically, as opposed to a user clicking on a button, right, okay. And then here we're gonna say const, and here, I don't actually care about reading from the adoptedPet, I only care about writing to it. So I'm just gonna put _ here to signify to future self, I don't care what this is, right?

And I only care about setAdoptedPet, = useContext, with AdoptedPetContext passed into there. Now this is gonna emit some ESLint errors because it doesn't like this, but we'll fix that here in a second. So down here on Yes, onClick, We're gonna run a function. And inside of that function, we're gonna setAdoptedPet to be pet, and we're going to navigate to /, setAdoptedPet, right?

Cuz if they click Yes, I want to adopt it, we want to set the current pet, whatever the pet is, as the adopted pet in context. And then we'll navigate them back to the homepage. Because we wanna get them off the details page to acknowledge yes, you did it, congratulations.

So one more thing here, we have this ESLint error. It's like hey, you're declaring this, but not using it, which is intentional, right? I'm intentionally declaring it and not using it. You can either go set ESLint to say like hey, if anything's just called _, ignore it, which is probably what I would typically do.

Or I'm just gonna click this and say Disable no-unused-var for this line. So it'll generate that comment for me, which ignores that line. Totally up to you how you wanna do it. Since I'm just gonna do it once here, I'm just gonna ignore this with this comment. Or you could totally call this a hook, and then use index one, yeah.

>> As far as using context, would we separate them into separate context with a bigger app? Or would you kind of snowball it into one giant context that's shared amongst the app?
>> Sure, no, that's a really good question, both are valid. If you're gonna snowball it into a big store, right, is what should it be called at that point, you've basically recreated Redux at some point, right?

At which point, maybe just use Redux, right? Cuz that's exactly what Redux is supposed to be. But I have seen people basically come in here, where it's app.jsx? We haven't talked about it, we'll talk about it in intermediate React. But there's another hook called useReducer, which is basically Reduxesque, right?

And then you can use useReducer with context, right? And then you have basically created Redux light using React state. That's how I would do that, if you wanted to do it that way, and you didn't want to use Redux. I'm not gonna talk about how to use useReducer.

We'll just hop into intermediate React v5 and we'll talk about it, but for now, I wouldn't do that. That's totally valid, I don't ever do that. I'm either on the side of I'm gonna use some very lightweight context, or I'm gonna use Redux. And I don't see the middle ground of when I would wanna do that.

But I accept that someone could, right? I think it's a valid choice to make. So me, personally, I am going to use context for little bits of state like this. And if I started having too much app state, then I move into a more robust solution like Redux Toolkit.

Hopefully that's sufficiently nuanced. Okay. So we are now writing to our context, but we are not reading from our context. So I need you to hop over to searchparams.jsx.
>> Before we get into it, can we do one more question?
>> Sure.
>> Where's the setAdoptedPet coming from?

It doesn't look like we're passing it from the app. We just have adoptedPet = useState.
>> Yes, so remember how useState usually looks, right? Typically I'm doing something like, let's say, theme and setTheme = useState, like this, right? And this is like a dark mode or something like that, right?

It's an array of two things, right? Here, I'm not destructuring like I am here, this is an array of two things. So adoptedPet is a whole hook. If this makes you feel better, we can actually just call it adoptedPetHook. So this is an array of two thing. If I mouse over it, you'll actually see the type, right?

Where it's a dispatch function and some amount of state. So it's coming from this, in other words, it is there, this is an array of two things. And then if you go down, or if you go into details.jsx, here, we are destructuring the two item array. So let us go read from, State in SearchParams.

Okay, so at the top, we have useState here, please import as well useContext again. And we're going to import AdoptedPetContext from AdoptedPetContext. Here we're gonna say const adoptedPet, = useContext(AdoptedPetContext). So again, this is an array of two things. This does have a dispatch function here, so it does have setAdoptedPet as well coming in, but I don't need it, right?

You can put an another _ here to just signify I'm not going to write to this. Or in my case, I just omit it, cuz I don't need it, right? So now this is going to be reading from the AdoptedPetContext. And here this is gonna be whatever the AdoptedPet is.

Okay, and then here just inside the form, I'm gonna put one of these turn areas here. So if I have an adoptedPet, I'm gonna display div className ="pet image-container" like that. And then I'm gonna have an image src = adoptedPet.images(0), and an alt of Okay, and then otherwise, display nothing, cuz you haven't adopted a pet.

Right, so otherwise it'll display nothing, cuz null means display nothing, right? If we have a pet, display all of this. Or if we've displayed, or if we've adopted a pet, if we haven't, then display nothing. So now if we go over to our app, notice that there's nothing here.

If I come here, click to Luna and I say Adopt Luna, Yes, now I have Luna right there, right? If I come down here to Beam, and I say Adopt Beam, and I click Yes, now Beam is up there. So that is how context works. Hopefully you're seeing I was like this is useful.

Because now I can read anywhere that I can get inside of, which for me is my entire app, right? This AdoptedPetContext, anywhere inside of my entire application, I can read and write to this context. But I'm hoping you also see the danger of, imagine you're just looking at this, and you're like, where does this context come from, right?

There's indirection, and if there's one thing that I don't like, it's indirection, and magic, and all those things when it comes to code. I like it being very explicit so I can read where stuff is coming from, where it's going, how it's modified. Just makes debugging, and reading, and understanding your application easier if that's the case.

So please understand the trade-off, only use it here when you need to. And if you start getting into having lots and lots of contexts in your application, consider using something like Redux, or MobX, or something like that.

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