If you already have a subscription, you can sign in.
Enjoy free content straight from your inbox 💌
00:00
Let's put into practice our conceptual knowledge of using React context to manage the shared client size state used by multiple pages of our next year's application. For this lesson, we will create a shopping cart sample that contains two pages, a courses page where you can add different courses to your shopping cart, and then a checkout page that also shows the shopping cart items. Additionally, in the nav we can always see how many items we have in our cart. We kick off by defining a few core types. We define the type for the course, which will have an ID title and a description along with the data structure that we will use to maintain our cart,
00:33
which will be a simple JavaScript map. The context in React is a client only component, which means that if you want to use it, we have to be within a used client directive. We bring in the core types that we've defined along with the few utilities from React, create context, we'll create the context props with children so that the provider can accept children as a prop use so that we can read a value from the context. And finally, the internal instrument that we will use to manage the state is going to be simply use state. The first utility that we will build is there to simply create the card store. We will not export this
01:05
because it should only be used by the provider, which we will define in the same file. As we mentioned, our store will internally operate on use state and it'll be maintaining an instance of the cart status structure that we defined within our types. The cart store is going to be a bunch of getters and actions which will utilize this internal state. We have two utilities, one to get all the courses within the cart and another to check if a particular course is in the cart. As an aside, as we covered within our JavaScript course, this has function is the reason why we chose to use a map. Next, we have a few methods that can be used
01:37
to update the current state. We have add course that takes a course and adds it to the map. Note that immutability is a big concept when using U State, which is why we are creating a new map. With the additional course added, then we have remove course, which removes the course with the given ID from the state and once more for this, we create a new map but filter out the item that we want to remove. And finally we have clear cut, which completely REIT initializes the courses with the new map. Note that there is nothing next year specific up till this point. We have simply built a hook that returns an object that manages some state.
02:08
This object is what we are calling a store by using the return type, which is something that we learned within our TypeScript course. Now we jump into the next year specific part, which is how do we create the store and then consume it within different client components. The answer that we've already covered conceptually is that we will use context, so we create a new context which will either store the card store, or initially it'll be null. And then we create a card store provider, which will provide an instance of the store to all of its children. Internally, it uses our utility to create the card store and then uses the context provider
02:42
to pass it down as a value. That's it for creating and providing the card store. Next step, we have to consume the card store, and for this we create a new hook. Within this hook. We simply read the value from the card store context to get the card store note that we initialize the context null, and if we still find that it is Null, it means that we were not rendered within a card store provider and therefore we throw an error. Otherwise, we have that shared card store instance created by the provider, which is what we return. If you've watched our lessons on context within the React course, this is pretty idiomatic context code. That's it for the creation of our store.
03:14
Now we just need to initialize it somewhere. By rendering the provider for this demo, we will make this client side state store available in our entire application by rendering it in the root layout. Within the root layout. We import our newly created card store provider from the card store context, and then we wrap all of the children off our application within this card store provider. Note that as we discussed within our lesson on the principles of client state management, we can render a client component such as the card state provider within a server component, which is the root layout within the provider. We also render out a header that displays the links
03:48
to the different pages along with the count of the current items in the cart. Since we are rendering the header within the root layout, it'll be visible on all the pages. So let's create this header component since it'll read the card store context. It needs to be a client component, which is why we start off with the use client directive. We import the styles along with the link component. And finally, we bring in the use card store from our card store context. This will allow us to display the count of the items within the cart within our component. We start off by getting the cart store from the cart store context, and then we fetch the courses
04:20
that are currently present within the cart. In the rendering of the component, we render out two simple links, one to the courses page and one to the checkout page, and then we display the count of the courses within the cart using the value that we fetched from the cart store. Notice how easy our client side user interface has become by maintaining all of this state within a single store with the header created. Let's work on our two pages. Starting off with the courses page. This is going to be a server page because we are going to use an external service to load the available courses. However, we know that we cannot use context on a server page
04:53
because it maintains the client side stage for a particular browser instance, which is why for the interactive portions of our page, we will create a new client component. And for this client component, we pass in the courses that we have fetched on the server. Note that we are calling this component page client, and we will create this module right next to the page in a file called page dot client. It is common to have a server component that loads data that is only available on the server and then pass it down as a prop to a client page, which will then make it in directive. This is called the page client pattern. Within the page client, of course, we start off with the use client directive.
05:26
We import some styles, we bring in the course type, and we bring in the use card store from the card store context. For the component, we accept the server provided courses as a prop, and then within the component we get the card store from the context. In terms of rendering, we render some simple copy, like a heading and a subheading, and then we follow this by rendering a list of all the courses. For this, we map through the courses provided by the server. For each of them we render out an image along with course details, and this is where the fun part comes in. Within the course details, we have the action buttons,
05:59
and to show the correct action button, we use the card store to see if this particular course is already present within the cart. And if this course is present within the cart, we render the remove from cart button and wire it to the card store dot remove course action. Otherwise, we show the add cart button and wire it to the card store.at course action. And that's it for the interactive portions of this component. We wrap it up by showing some additional copy, like the course title and the course description. With our course page created, the only thing that's left to do is to create the checkout page for the checkout page. We don't need any server information,
06:30
which is why we will render it all within a single client component, and therefore we start off with a use client directive. Once more, we bring in some styles and the use card store utility from the card store context within the component. We get the card store from the context, and then we get the current courses that are present within the cart by using this card store. Now all that we have to render within this page are the list of courses that are present within the cart, so within the render portion of this component, we start off by rendering a simple heading, and then we check if we have any courses within the cart. And if we don't, we show a message your cart is empty. Otherwise, we show the heading courses in cart
07:05
and then iterate over the courses in cart and render out simple list items containing the course titles as an additional feature. We allow the user to play the cart at this point by rendering a button via the card store clear cart action once more. Moving our straightforward logic into the cart store has greatly simplified this next day's page. Congratulations on following along, building this application from scratch, let's play around with it in the browser to see our hard work in action. On the courses page, we list out the different courses that we fetch from the server with the action buttons applied to our cart store, and as we add the different items into the cart,
07:39
we can see the current cart count within the nav. Then within the checkout page, we can also see the current courses that are present within the cart, and as we make modifications to our cart from the courses page, for example, we remove an item, the cart count updates, and that course also disappears from a checkout page. Finally, from a checkout page, we can clear the cart to remove all the courses, and now if you visit the courses page, you can see that all the courses can once more be added to the cart.