This video is available to students only

Contexts can be Used to Share Functions within an App Too

Context doesn't necessarily need to live at the top level of a component to be useful.

Context can be employed at all different levels of a React app, not just the root level#

Our last lesson was a big one: we made a big context Provider to wrap the entire application, and not only did we do that, but we also ended up moving some state in a child into the parent because they shared data from the same custom hook.

Now, we're about to dive deeper into Hardware Handler, and I'll demonstrate a couple of instances where we can employ smaller contexts to make our code cleaner and clearer.

Context doesn't just have to live high up in our React apps, though. It can also be small and nimble and very focused in its purpose, which is how we'll use it in this lesson.

Checkout API functions take center stage once more#

In our app, there are two instances where checkout API calls are passed from parent components: in the <ProductList> component, where we display all the individual products that can be added to the checkout, and in the <Checkout> component where each item rendered can be removed.

Now both of these components have a different checkout API call they contain and pass on to their own children.

We're going to take these components one at a time, create contexts for them so that we no longer need to pass the functions as props, and see how contexts can be employed all up and down an application in large and small ways.

Let's focus on the <Checkout> component first.

Create a new CheckoutFunctionContext.js file#

Inside of the <Checkout> component is a function named removeItemFromCheckout. This function is passed to the individual <CheckoutItem> components that are rendered for each item present.

This is the function I want to make a context for.

As with our previous context, inside of the context/ folder, create a new file named CheckoutFunctionContext.js.

And create a context code shell in there.

Be specific in naming your contexts

I know the name for this new context file is long, but bear with me.

Since we've already got one context that's about checkout, we have to be specific in naming another one responsible for another piece of checkout. This is not an uncommon occurrence in large apps.

One of the hardest things about programming is naming variables, but don't be afraid to have long, specific names for files — your IDE will help with the autocompletion to make sure things stay spelled right after initial declaration.

Now, since we've already identified the function that we want this context to handle, we can add it as a default value inside of this new context file.

After this, we're ready to add this context to our <Checkout> component.

Add the new context to Checkout.js#

Back over in our Checkout.js file, we'll import the new CheckoutFunctionContext object and wrap it as a Provider around part of the JSX.

First, import the function at the top of the file:

Then, establish it as a Provider in the file, and assign the local function of removeItemFromCheckout as its value to replace our default value.

Contexts can work inside of specific pieces of JSX, not only the whole thing

Notice that I'm only wrapping the context provider around where we loop over the checkout items to render them.

This is one of the cool things about React's Context API — you don't need to wrap the whole JSX inside context for it to work, only the child components that will need to access the context object for those values.

Delete the removeItemFromCheckout prop#

Right after wrapping the JSX with the <CheckoutItem> component, delete the removeItemFromCheckout prop being passed to the component — it's no longer needed now that we'll be using context instead.

Now we're ready to open up our <CheckoutItem> component.

Update the CheckoutItem.js file to access the useContext Hook#

After adding the context Provider to the parent <Checkout> component, it's time to add the consumer to the child <CheckoutItem> component.

Inside of the CheckoutItem.js file, we'll import the useContext Hook and the CheckoutFunctionContext.js context file.

Then, remove the destructured prop of removeItemFromCheckout from the component declaration, and declare a local variable of checkoutFunctionContext set equal to the context we imported above wrapped in our useContext Hook.

And in the JSX below, in the <button> element, update the onClick function.

Great, we're making really good progress. Before we leave this component, though, your ESLint plugin should be going crazy.

Fix <CheckoutItem>'s ESLint errors#

At first glance, this CheckoutItem.js file sets off all sorts of ESLint alarm bells, but it's really not all that bad — we can handle these issues.

ESLint errors present in the `CheckoutItems.js` file

The first issue is that our <button> element in our JSX is missing an explicit type. This error is happening because the default value of type attribute for the button HTML element is "submit" which is often not the desired behavior and may lead to unexpected page reloads.

Start a new discussion. All notification go to the author.