‫Now that we know how to use the Context API
‫in practice,
‫we can take it to the next level
‫and implement a custom Provider component
‫as well as a custom hook to then consume the data.
‫Now, I want to start by saying
‫that the implementation that we have right now
‫is actually perfectly fine.
‫So it works great.
‫And so in many applications, this is more than enough.
‫However, as I said at the beginning of the lecture,
‫we can now make this even more advanced
‫by implementing some more advanced patterns.
‫And so let's now do that.
‫So the idea is basically to remove all the state
‫and state updating logic, all from this component
‫and place it into our own custom Context Provider component.
‫So we will then have all the state
‫and we will then provide that
‫using context into our application.
‫So it's basically just a refactoring
‫of what we already have
‫but the functionality will stay exactly the same
‫and we still will have all three parts.
‫So creating the context, then providing a value,
‫and then reading it.
‫We will just have these different parts in different files.
‫Okay, so let's now start implementing that.
‫And the first thing is to, once again, duplicating this file
‫and then calling it version one
‫so we can also keep the original version.
‫Okay.
‫And then next, let's create a new component
‫called PostContext.js.
‫Okay.
‫And here,
‫let's actually create this function manually ourselves.
‫So PostContext,
‫and we will then later also export it.
‫And basically what we do now is to grab all this stuff,
‫so everything that is related to the context,
‫and place it into that other file.
‫So let's cut that, place that here,
‫and then we should probably import this.
‫So one good way of doing that
‫is to delete part of the string.
‫And so then we get our auto complete back
‫where we just have to hit Enter,
‫and then that gets automatically imported.
‫Now here, not sure why we're getting this error.
‫Ah, and it's just because
‫we of course now already have this variable
‫called PostContext.
‫And so actually I want this not to be called PostContext
‫but the PostProvider.
‫So this then makes the intention of this component
‫a bit more clear.
‫So basically from here,
‫we will export or we will return a provider.
‫So that's why we call this the PostProvider.
‫All right?
‫And now let's grip all the state
‫and the state updating logic from here.
‫So all of this, but of course not this effect.
‫And then let's place that here.
‫And then we are again, missing some stuff here.
‫So let's use that trick again to import useState.
‫And then we need to also copy this function right here.
‫And here we cannot cut it
‫because we actually need it in another function.
‫So let's just copy it and place that here,
‫and then we also need to copy this.
‫So probably we should export all of this here
‫into some other special file
‫but here we just want to keep it very simple.
‫Okay.
‫Well, actually we also removed this state,
‫so about the dark mode.
‫So let's place that back right here,
‫and then what we want is to also grab this.
‫So cut it and remove this one here as well.
‫All right, so again, we are just refactoring everything here
‫into this provider
‫so this component will just be another React component
‫and so it needs to return some JSX.
‫And so that JSX will be this provider.
‫Let's close it,
‫and for now, we are good like this.
‫And so here, I think we now removed all our errors.
‫Now we have some problems right here
‫where we now are trying to read from the PostContext
‫which no longer exists,
‫but let's take care of that later.
‫So what we want to do now
‫is to use that PostProvider here
‫exactly in the same way that we used the provider before.
‫So exactly what we had here earlier.
‫So let's actually for now export this from here.
‫So PostProvider to an export default for now.
‫And so then here we are able to just import PostProvider
‫like this.
‫All right.
‫Place that here.
‫But that will actually still not work
‫because watch what's happening right now.
‫So we are passing all of these children here
‫into the PostProvider component, right?
‫But then all that we do here
‫is to return this PostContext.Provider
‫but we're not doing anything with the children.
‫And let me demonstrate that here in the application.
‫But before we do that,
‫we actually need to now export this PostContext
‫so that we can use it here in App.
‫So let's now instead of the default export,
‫export him like this.
‫So a named export.
‫So PostContext,
‫and so let's now here import this as name imports as well.
‫So exactly in the same way as we exported them.
‫So PostContext, and beautiful.
‫So that basically fixes it
‫even though now as I mentioned before,
‫we have an empty page.
‫And so the reason for that
‫is that all we are doing now
‫is to return this Context Provider, right?
‫So again,
‫right here we have the PostProvider component,
‫but all this does is to return this PostContext.Provider.
‫And so then that's what we see in our tree.
‫And so what we need to do now
‫is to accept the children prop like this
‫and then place the children back here.
‫And with that, then our application works again.
‫Let's go back to normal mode and let's try to search.
‫And yeah,
‫so everything works the same
‫but now we created ourselves
‫our own custom Context Provider component,
‫which is this PostProvider.
‫All right?
‫And with this,
‫we really cleaned up tremendously this App file,
‫so our parent component.
‫And here actually we can make this even a bit cleaner
‫because this section here in this button
‫of course don't need this provider.
‫And so with this, I think it looks even a bit better.
‫So it's important that you understand what we just did here.
‫So we created this PostProvider component
‫which we now wrap around all our other components,
‫and you can always compare that with the V1 file
‫that we created earlier.
‫So we pass this here into the opening and the closing tag
‫and so, therefore,
‫these will become the children of this component.
‫So then we use the children prop here
‫and then we wrap all these children
‫inside the PostContext Provider just like we had before.
‫And so by doing that,
‫we could place all the state and the state update logic
‫into its own separate context file,
‫which then cleaned up tremendously
‫our main component that we have here.
‫So this app component.
‫And we could even do the same thing here
‫with this fake dark mode, but let's keep it simple here.
‫So here we could remove that from here, this comment,
‫and place that here,
‫but that's not really important.
‫So with this, we finished the first part of the lecture
‫which was to create the Context Provider component.
‫But now remember how I told you
‫that we are also going to create our own custom hook?
‫And so let's see what that means.
‫So right now to consume the context,
‫we are always using this usecontext hook
‫and then we pass in the PostContext object.
‫And this works great,
‫but over time after using this many, many times,
‫you will notice that it can become a bit annoying
‫to always have to write this PostContext here.
‫So basically this part here
‫is always repeated over and over again
‫in all the components
‫where we actually read the value from the context.
‫And so basically we can encapsulate this part
‫into its own custom hook.
‫So let's come back here into this file
‫and then create it right here as well.
‫So that's a very common pattern
‫that many developers use these days.
‫So basically placing this Context Provider component
‫and then the corresponding hook all into the same file.
‫So let's call this one here, usePosts,
‫and we don't need any argument then.
‫And so here, let's then get the value out of the context,
‫so the entire value which we will then return
‫so that in our components we can destructure it.
‫And so now we will use the useContext hook right here.
‫So using it here and then passing in the PostContext
‫just like we did before.
‫And now we can return the context like this,
‫and then instead of returning this context here,
‫we can leave it encapsulated inside this file
‫and instead export this custom hook.
‫So with this, we then basically create like an API
‫for this context.
‫So again, instead of exposing the context object itself,
‫we just expose a function
‫with which we can then access that.
‫Okay?
‫So this one is nicely called usePosts.
‫And so let's use that here instead of the PostContext.
‫So usePosts, and now we just everywhere replace this.
‫So I will now use Command or Control + D,
‫which again is this one here.
‫So add next occurrence to select all of them.
‫And so then we just use usePosts,
‫and beautiful.
‫So it works again.
‫And if you ask me, this is now a lot cleaner.
‫So we don't have to think
‫about the name of the context anymore,
‫we just write usePosts
‫and then we get whatever we want from there.
‫Okay.
‫Now let me just show you something
‫which is,
‫for example, trying to use that custom hook right here.
‫So usePosts right here
‫and then let's log that to the console.
‫So what do you think is going to happen?
‫What do you think this x will be?
‫Well, it is undefined.
‫So why do you think that is?
‫Why is the context value suddenly undefined?
‫Well, all we need to do is to look at our componentry.
‫So we tried to use the context here inside of App
‫but the context only provides the value
‫to all its children components.
‫So only to all of these that are below the provider.
‫So basically only to these ones right here
‫and to ones that are inside it,
‫but not right here.
‫And so this could lead
‫to some hard-to-find bugs in a larger application.
‫And so let's now do something against this.
‫So basically to prevent someone from using this hook,
‫so to accessing the context value where they shouldn't.
‫So notice how the context value was undefined.
‫And so what we can do is to test for that.
‫So we can check if the context is undefined
‫then let's just throw a new error.
‫And then let's let the developer know
‫that PostContext was used outside of the PostProvider.
‫And yeah, there we go.
‫So this is actually a lot better
‫even though normally we don't like errors,
‫(chuckles) but in a situation like this,
‫it's actually a lot better to have directly an error here
‫than maybe having the developer think
‫that this somehow works.
‫So with this,
‫they know immediately that this cannot work.
‫So that's why we should always create an error
‫in the situation where we are trying to access the context
‫where we actually cannot.
‫Okay.
‫And this is all I wanted to show you
‫for this advanced pattern.
‫So again, it is composed of two parts basically.
‫First, the PostProvider
‫and then our own custom hooks
‫to read the value out of the context.
‫And I'm showing this to you
‫because this is basically like a recipe
‫that you can always follow in all your own projects
‫when you want to use the Context API.
‫So we always do this in the exact same way.
‫So we create a context,
‫then we create our own Provider component
‫which receives to the children
‫so that we can then use it like this here
‫and then we pass the value in there,
‫and then of course, also return the children here.
‫And then in the end, we always have this own custom hook.
‫So again, always the same recipe
‫that you can start using in your own applications.
‫Great.
‫So now we know really well
‫how to use the Context API in practice.
‫And so let's now go back
‫to talking a little bit more
‫about state management
‫and how the Context API fits into that picture.