Setting Up Contexts To Share Functions Within A React App
Context doesn't necessarily need to live at the top level of a component to be useful.
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the The newline Guide to Modernizing an Enterprise React App course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to The newline Guide to Modernizing an Enterprise React App, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:14] Our last lesson was a big one. We made a big context provider to wrap the entire application, and not only that, but we also ended up moving some state in a child into the parent because they shared data from the same custom hook.
[00:15 - 00:34] Now we're about to dive deeper into hardware handler, and I'll demonstrate a couple 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.
[00:35 - 00:58] In our app, there are two instances where checkout API calls are passed from parent components in the product list 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.
[00:59 - 01:14] 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.
[01:15 - 01:25] Inside of the checkout component is a function named removeItemFromCheckOut. This function is passed to the individual checkout item components that are rendered for each item present.
[01:26 - 01:46] 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 checkout function context.js and create a context code shell in here.
[01:47 - 02:13] Import, create context from react, create a constant arrow function that we're going to call checkout function context, which we will create an empty shell for the moment, and finally export it as a default. Here's a tip, be specific in naming your contexts.
[02:14 - 02:27] I know the name for this new context file is long, but bear with me. Since we already have one context that's about checkout, we have to be specific in naming another one that's responsible for another piece of the checkout.
[02:28 - 02:38] 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.
[02:39 - 02:53] Your IDE will help with the auto completion to make sure that things stay spelled right after initial declaration. Now, since we have 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.
[02:54 - 03:15] So we are going to name it as remove item from checkout. And we're going to make this an empty arrow function, and then I am going to fix an error, which I didn't even realize I had made, which was I made an error function out of this instead of using create context.
[03:16 - 03:23] And anybody who caught that, good job. So after this, we're ready to add this to our checkout component.
[03:24 - 03:49] So back over in our checkout.js file, we are going to import the new checkout function context object and wrap it as a provider around part of our JSX. So import it, check out function context, and then establish it as a provider in the file and assign the local function of remove item from checkout as its value to replace our default value.
[03:50 - 03:59] So right down here, where we have our checkout list wrapper, that's where it needs remove item from checkout. So this is what we're going to wrap our provider around.
[04:00 - 04:14] So we have checkout function provider, and then we give it a value equals double curly braces, remove item from checkout. And then we will close that tag, and we will create our closing tag as well.
[04:15 - 04:23] Good. So notice that I'm only wrapping the context provider around where we loop over the checkout items to render them.
[04:24 - 04:32] This is one of the cool things about React's context API. You don't need to wrap your whole JSX inside of context for it to work.
[04:33 - 04:47] Only the child components that will need to access the context object for those values. So right after wrapping the JSX with checkout item, we can delete the remove item from checkout prop that is being passed to the component.
[04:48 - 04:54] It's no longer needed now that we'll be using context instead. And now we are ready to open up our checkout item component.
[04:55 - 05:17] So inside the checkout item file, we're going to import the use context hook, and we are going to import the checkout function context JS file. So we can remove this use of react and bring in use context instead, and import checkout function context.
[05:18 - 05:46] And then we can remove the destructured prop of remove item from checkout from our component declaration and declare a local variable of checkout function context, which we will set equal to the context that we imported above with our use context hook. bells, And in the JSX, in the button element, update the onclick function.
[05:47 - 05:57] Great, we're making really good progress. Before we leave this component though, your ES lint plugin should be going crazy.
[05:58 - 06:25] but it's not really all that bad. We can handle these issues. 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 is submit, which is often not the desired behavior and may lead to unexpected page reloads.
[06:26 - 06:42] Since our button is actually making an API request to the server and removing an item previously in the checkout, we should add the type of submit to it. So add this line to your element right under button, give it a type of submit.
[06:43 - 06:49] One ES lint error fixed, six to go. And these are errors that we've seen before.
[06:50 - 06:54] It's our old friend, the missing prop types. We know how to fix this one.
[06:55 - 07:07] Import prop types at the top of your file. And at the bottom, define all the prop types for our item prop that is still passed into this component.
[07:08 - 07:31] Since this is an object, we're going to use the prop type of shape and then declare all of the properties in this object. So we have ID, which is a prop types of number and is required.
[07:32 - 07:54] We have name, which is a prop types of string and is required. We have brand, also prop types of string is required description, which is prop types of string and is required.
[07:55 - 08:14] And finally, retail price, which is prop types of number and is required. And then we say that all of these item shapes is required.
[08:15 - 08:21] That should resolve the rest of our errors. So let's call this refactor done and move on to our next context component.
[08:22 - 08:34] Now it's time to look at our product list component again, which passes a function from the parent to the product child that allows us to add items to the checkout. So open up product list.
[08:35 - 08:45] And we see that we have this function add item to check out, which is defined all the way up here. Add item to check out.
[08:46 - 08:53] So in this component, this is the function that I want to make a context for. So to start, we are going to need to make another new context file.
[08:54 - 09:06] So once again, inside of our context folder, we will create a new file. And we are going to name it product function context.js.
[09:07 - 09:14] And then we'll add the following code, which should be becoming quite familiar to you. Import create context from react.
[09:15 - 09:22] Declare a const of product function context. And then create context.
[09:23 - 09:33] Make it an empty function for now. And we will put add item to check out inside of here as an empty as an empty function.
[09:34 - 09:41] And then of course export this guy. Export default product function context.
[09:42 - 09:46] Cool. And with that defined, head back over to product list.
[09:47 - 09:57] So back in product list, we'll import our newly defined context. And this will be where our context provider lives.
[09:58 - 10:14] So where the JSX is rendered further down in the component, we'll declare our product function context provider. And we will wrap it around our product component, since that is the only piece of the JSX that actually needs access to this provider.
[10:15 - 10:32] And give it a value that is equal to add item to check out. And then down here, after this div, we will close that provider.
[10:33 - 10:42] Now we can remove the add item to check out prop that is being passed to product. And we can open up product to make our final changes.
[10:43 - 10:45] Great. We're in the home stretch now.
[10:46 - 10:54] Open the product component that lives inside of our components product folder. And we have a bit of refactoring to do to make this component ready to use context.
[10:55 - 11:04] First, we are going to import the use context hook from react. And we are also going to import our product function context.
[11:05 - 11:19] Next, we're going to update this pure functional component that doesn't even have a return statement and make it ready to accept a local context variable. Add some curly braces and a return before the JSX.
[11:20 - 11:43] And then declare a const of product function context equal to the use context and pass in the product function context that we imported. Now you can go ahead and delete the add item to check out because that will be supplied by context from now on.
[11:44 - 11:56] And we will take this and we will update our button to start using that context instead. Once again, we have a lot of ES lint errors that are popping up in our terminal .
[11:57 - 12:05] So let's declutter these and take care of them. These errors are almost exactly the same as the ones that we saw in the checkout item component.
[12:06 - 12:18] The first error being button is missing a type. So once again, this should have a type of submit because we are making a form submission of a sort.
[12:19 - 12:28] And the other error that we're getting is prop types rearing its ugly head once again. If you don't know how to fix this one by now, I'm really not doing my job very well.
[12:29 - 12:46] Import the library for prop types at the top of this function. And then at the bottom of this function, use the prop types dot shape type to define all the expected properties within this object.
[12:47 - 13:01] They are verbatim what they were for checkout item. So I'm actually just going to go over and copy them from here and paste them in and rename this from checkout item to product.
[13:02 - 13:12] One more change to make. With those updates done, our ES lint errors should have disappeared out of this component and we're ready to move on to a quick smoke test of hardware handler's functionality.
[13:13 - 13:22] As we have done countless times before with this application, let's fire it up and see how it works. CD into your client folder and run yarnstart.
[13:23 - 13:31] So the two components that we're testing are the product and the checkout item components. nested within the product list and checkout components.
[13:32 - 13:40] Once the app is running, navigate to the my products page and add a few items to the checkout. Do they successfully get added?
[13:41 - 13:43] Sure do. So then head over to the checkout.
[13:44 - 13:47] Do the items appear there? Yep, looks like it.
[13:48 - 13:50] Super. Now remove a couple.
[13:51 - 13:52] Remove. Remove.
[13:53 - 13:57] The items should disappear just as they always have. Great.
[13:58 - 14:04] After confirming that these portions of the app still work, we can call this lesson done. Fantastic job.
[14:05 - 14:12] I hope that this gives you a better idea of the myriad ways that context can be applied in a React application to great effect.