You want to use Redux in your NextJS 13
application that uses the app directory? Well, you've come to the right place. This tiny but mighty little Pokemon
application that we're going to build is going to show us how to do server side
rendering, how to move the store that's in a server into the client,
and how to do our RTK query with the new API
standard that’s in the app director. It's all here. I'm so excited to get right into it. But before we do that, I do want to say
that we have a sponsor for this week and that Scribe. More about them in a bit. Let's get right into it. All right.
This is the app that we're going to build. We have a database of Pokemon
on an API endpoint that we can then use dynamically to just search. There's also a pure SSR route that shows you exactly how to do Redux,
but only in the SSR context. And there is the API route that gives us back the list of Pokemon. And then when we do a question mark, name, it filters down
to just the Pokemon that we want. This is the application
we're going to build. It is not a full CRUD application,
but I don't think you need that. What we’re really looking to explore. here is how to use the Redux store,
which you're probably already familiar with in the context of Next 13 with that app directory,
with the new API structure and how to do it in
both the client side context, which we're very familiar with,
but also the server side context, which we're not so familiar with and
how to bridge the gap between those two. Now let's go and start building
our Next JS 13 application that uses Redux to create this
cool Pokemon search page. We're going to use NPX to do create
next app with the latest, which is going to give us
NextJS 13 at the latest build. We're going to call that NextJS 13 Pokemon and we're going to opt
for the experimental app. We want to use TypeScript,
we want to use eslint, we do want to use that src directory
and this import alias is really nice. You use @ and @ is the src directory. So you can just do @ and then slash and then whatever
you have in your source directory. All right, let's bring it up. Now, I did mention that this week's
sponsor is Scribe. I'm going to use them right now to document
how to start up our application. So I'm going to go over here
to the Scribe desktop application. It start recording,
and then we're bringing up our terminal and then I'm going to do pnpm
to make sure that we're all installed and then I'm going to do pnpm run
dev to run it. Then I'm going to click on localhost. This is our NextJS 13 starter. And for documentation, I want to show folks that you can click
on the docs link and get the beta docs or you can click on the templates link
and get some sweet looking templates for NextJS. Or you can click on deploy
and it will walk you through how to deploy this on Vercel. Seems like a good place to end. So I'm going to stop recording
on my Scribe Desktop and then Scribe brings up the workflow that I just did
to make it super easy to document. You can see that it captured right at the beginning
that I did control back-tick to it to bring up that console. We have our image for the console
that I can then actually go in and edit. Check this out. I can go and go down and kind of crop it
to where I need it to be. How cool is that? Think about how easy this is going
to make your documentation and it tracks every single thing that I did
as I transitioned in the browser. You can see that I went to my page
and then I went to the docs and then I went over to the templates
and it's all just there, all ready to go. All you need to do is fill in the text. It's really cool. Now that we're done editing and click
the done editing button and we can see that we are basically live
with this. In fact, we can go and share it. And there's so many ways to share. We could export this as markdown
and just put it off in a dev.to article. How cool is that? Or we could just share it directly
with our team by just copying that link and then pasting it into, for example,
the README of this project. Or if I wanted to put it in the team
documentation, I can just paste a link to it
in there. It's great. If you're as excited as I am about Scribe
and adding it to your documentation workflow, be sure to go
to scribe.how/jackherrington-march. There's a link to that in the description right down below and you'll be helping out
not just yourself when it comes to building
great documentation, but also be helping out this channel
which I fully support. Okay, let's get back into the action. So fundamentally
we need an API to talk to. We're going to use our Pokemon data
set for that and that's going to allow us to test fetching that data
both off the server and off the client. So let's go
build out our API for our Pokemon. So if we look at our directories, we have source app now in there,
we've got API, it's got a basic root that were just returns
hello next to us from the get. You use different verbs now
and uppercase get is for GET requests. So we're going to go and bring in
some pokemon into the src directory. This is Pokémon JSON. It has a list of all of our pokemon. Again,
all of this code is available to you in GitHub in the link in the description
right down below. Let's go and bring that into a new route
that we're going to build called Search. So in API, we want to build
a new folder called Search and then in there a new file called route.tsx. So that's going to give us slash API
slash search and anything going to that endpoint is going to go to this file
first thing we want to do or bring in next response that's going to allow us
to process the response and send one back when we want to bring in our Pokemon
and we're going to use that nifty slash because that is now relative
to anything in source. All right, let's create a GET request and we'll get the search parameters
from the URL. It no longer does the URL query
passing for us, but it's no big deal. We just knew your URL and get that from
that. We're going to get the name and then we're going to filter down
our Pokemon based on that name. So going to do slash API slash search question mark, name equals, and then the name that gives us back our Pokémon data. And then we can simply just return
a next response for the JSON with that data. But I don't want to overwhelm the client,
so I'm just going to use the top ten on the slice. So whatever we match, I'm
just going to use the top ten from that. Okay, let's start to build out
a UI on this thing. So I'll go over to the page directory
that's just the home page and I'm going to filter all of this down. I mean, for sure it's a beautiful page,
but we don't need all of it and I'm going to make a request
to that endpoint using fetch. But of course
we're going to get a little issue here because we're using a weight
and this isn't an async function. And that's the great thing about NextJS
13 in this app directory, when it comes to server side, only components like this one,
you can use an async function as opposed to using a synchronous function
like we normally do. Okay,
now that we should have our data there. So it's just JSON string of client and so we get there we go. Looks good. Kind of garbage. Let's go change up the CSS a little bit. So over here in global CSS, so I'm just going to get rid
of a lot of that and just go with a font family of Arial Helvetica
whatever and decently sized font. So now we've got our data. Let's format it up a little bit nicer. First, we need to define in TypeScript
what the topology of a Pokemon is. So let's go build a new file called types and then I'll drop in an interface
for Pokemon. Got an ID number, name type,
all the good stuff that you want to know from pokemon
if you want to go and extend our cool app now that we know what a pokemon is,
I want to go and have a nice little pokemon table
that just formats it nicely. So let's go and build a components
directory within source and then within that components directory a pokemon table. First,
we're bringing in our Pokemon definition and then we use it in our component
definition where we say the Pokemon table has a list of Pokemon an array of them,
and then this is just going to build out a simple table. It's got a header, it's got the pokemon
and the name and you can add on to this. If you want to try this out,
I'm going to go over to page.tsx and we'll import it,
see how nice that looks and it automatically hinted us
to where it was. So these Pokemon table there
and just give it our list of data. Okay, looks good. So why would we want
to bring Redux into this? Well, let's say that
we have a big component tree in this case. We're going to create a new component
called SSR Pokemon Table and we don't want to prop drill the data
from the page down to this Pokemon table. So how are we going to do that? We're going to use the Redux store
for that. So first off, let's go and build
our Pokemon SSR component. We'll call it SSR, Pokemon Table, and in there
it's going to bring in Pokemon Table and it's also going to have those Pokemon,
but it currently doesn't have access to that data. So let's get it access to the data
by bring in all of Redux and Redux Toolkit so you can get that data to that
Pokemon table. Alright I’m going to do npm
i to install Redux of course, the classic React Redux which binds it to React
and then the Redux Toolkit. Redux Toolkit is just a very handy
set of helper functions that makes it really easy
to define stories and slices and actions and all the good stuff
that we have in Redux. Now I'm going to rerun the server. Now I'll create a new directory for our Redux store
and I'll call it store. Seems like a decent thing to use now. I think that we're going to have a search slice and that search slice
is going to have the list of Pokemon plus the current search terms since
we want to end up building a search page. So the search slice is going to be
the slice of the store that manages search. So first off, we'll bring in Create Slice
because we want to create a slice. They'll bring in payload action
because that's important when we define the parts of the slice. And of course, we'll bring in our Pokemon,
which is the data that we're going to be using. So what does our state look like? Well, our state is going to have
our search string and it's going to have the startup
Pokemon. That's the initial set of Pokemon
that we got. The startup pokemon is just going to have
our server Pokemon in that initial set that we get during the page load
for the dynamic stuff that we use when we do a search, we're actually
just going to use the data that is stored within the RTK or React Toolkit query,
so we don't actually have to manage that. Now we'll create a slice. It's going to be a named search
and then have its initial state and then we need to give it some reducers. These are the functions
that you can call on the store in this case, set search
to go and set a search value. The payload action for that one
is just going be a string. You're just updating
the string of the search and then an action
to set the start up Pokemon. And this is what the page is going to use
to set the Pokemon in the store. So it's just going to set that startup
Pokemon to anything that's in the payload. And what do we export out of here? Well, we're going to export the set search
and set start to Pokemon actions,
which search Slice has created for us. That's one of the really great things about the Redux Toolkit is it gives you
all of these really handy functions so we don't have to define our actions
by defining them in the reducers here. It has already created actions for us and those actions are setSearch
and setStartupPokemon. Awesome. And we need to have the reducer
for this slice and that we export as the default. Now a slice is not a store,
so we need to go create the store, which is going to be our global store, which is going to bring in
any number of slices or APIs. So we'll create that on index.ts in here and we'll bring in ConfigureStore
from Redux Toolkit. Again, a very nice easy
way to create a Redux store. And we'll bring in our search slice
that we just created. Then we'll use that configure store
to create our store and we'll just give it our reducer,
which we'll put on search. And it's the search reducer that we got
as the default out of the search slice right here. Now, when we connect this to React Redux,
React Redux is typed, but it doesn't know
the schema for our store, so we need to give it the schema
for our store and our dispatcher. So what we do for
that is we export some types out of here. The root state is the
the total state of the store. It is the output of store. I get state any time you call store
to get state, you just get the whole store and we're going to get the return tab
out of that. Pretty simple. And then the app dispatch
is the type of the dispatch which is automatically created for us. You could do command-K command-I here and see that we have a search state,
which is the output of search. All right, now we have our store. Let's go over to page, that's X
and we'll set the data in the store. So we need to bring in our store first. So bring it in from @ store. And we're going to bring in the action
creator of setStartupPokemon. So with that,
we're going to just call store to dispatch and then we're going to call that action creators that startup Pokemon
and just give it the data. Let's see if this works. And it does, but it's because we’re
pointing at the wrong component. I'm looking at Pokemon Table here
and I'm giving it the data, so I want to look at this SSR Pokemon Table instead. All right. Yeah. Now there's nothing coming through because as I say, our Pokemon table isn't
actually connecting to the store yet. So let's connect it to the store. To do that
I'm just going to bring in the store and then here for the store to get state, search and then startup Pokemon. Hit save and go and there you go. Now that's an example of using Redux
during SSR time. Now, if you're building an e-commerce site
and you want to go and get all of the information about the product
and you want to have some images and you only want those to be rendered
on a server using React Server components because they're not dynamic, then
this is the way that you want to do that. Page is a React server component. It only runs on the server. We have no client side components yet,
so the only way that we can get data from and to the store is to directly connect
to the store directly call store, not dispatch, directly
call store to get state. If we're to use the React Redux hooks,
it would tell us that we can't do that because you can't use
hooks in a React server component context. So that's why we're not using React
Redux hooks here. Now, we do want to kind of lockdown this particular part of it
because we've now looked at SSR, and if that's all you're doing,
then I think having some example code that shows that only is good, someone go
take this page and I'm going to go create directory here called Pure
SSR inside of the app directory. And then inside of their page.tsx and I'll just paste off this in here and now if you just want to see how to do SSR, only then you can just look at this
pure SSR directory and it's going to have that before we've gone and added
any kind of client side craziness into it. So let's actually try this out. We can go over to our pure
SSR route in Arc and there you go. And you can see that
when you view the page source, we're getting all of the data in there. Ivysaur our Wartortle. So it's all being done on the server,
but it still uses Redux. Really nice. Okay, let's go back over to our home page, make sure that we're on the home page,
because now we're going to start using Redux both on the client
and on the server. It's really cool. Okay, let me close a few files here
so we don't get confused. They're going to turn our homepage into a search page, and to do that, I'm
going to create a search input component. That's
where we're going to type in our search. So I just bring in
a very simple search field, and then I'm going to bring that search
input into the page and replace this
as our Pokémon table with that hit save. And there we go. We've got our search input. Woo! Now I want to go and connect our search
input to our store. So I need to bring in a bunch of stuff
for the store itself. I'm going to bring in, these should seem
familiar, useDispatch and useSelector from React Redux,
the type selector hook from Redux. I'm going to bring in our setSearch and we are going to create our app
dispatch in our app selector. So let's check this out to see
does it work? Okay, so this is telling us
that we are bringing hooks into a React Server Component,
but is this a React Server Component? I mean, we want it to be dynamic, right? Well, how do we tell it that? Well, we need to tell it
that it's not a React Server Component, that it's a hybrid component or a client
component, whichever way you want to say it, a component that runs
both on the server and the client. And the way that we do
that is we put in the use client directive and now we can use those hooks. Cool. And notice we didn't even have to actually
call the hooks to get that error. We just brought in the hooks
and that was bad enough. Okay, now we're going to get
our dispatch in our search. The dispatch is what's going to allow us
to set values on the store and then search is going to give us
the value of the current search field. So we’ll just use value search. And then when we change, we're going to dispatch a set search action
creator with the target value. So let's try it out. Let's see. Okay, Now we've got a different error. This error is telling us
we don't have a provider. So if we go over here to useAppDispatch, well, on what store. useAppSelector okay. But on what store? You haven't
actually told us what the store is. So to do that, we need to
create a provider and give it the store. So I'm going to go over here
into components and create a new file called Provider, and that's going to bring in our store
as well as a React Redux provider. And then I'm going to give provider
our store call, but not good because we haven't
actually used provider yet. Okay. So now I need to bring our provider. I'm going to go bring that into our page
and then wrap our search and put in that looks pretty good. But how do we know it's working? Let's go over here to our Visual
Studio code, go back into our search input and then we just drop in here
div with that search looks great. Cool. So we know that we're getting
and setting from the store properly. All right. Now we also want to show a table right
below the search that shows the Pokemon that we found
and we are granted the default. No search pokemon
already through start up Pokemon. So let's see if we can get to that. So I'm going to bring in our Pokemon
table component and then get the start up pokemon and then just throw
the startup Pokemon at our table. Okay, let's see how we go. All right, well we have a table, but
we don't have any pokemon, so why is that? Well,
we haven't moved the state of the pokemon from the server to the client. To do that we need a client sign component
that takes the start up pokemon and then sets the store
on initialization on the client. So how can we get data
from the server to the client? Well, what's interesting to know
is for client side components use client components. Anything that comes in as a property
is serialized from the server to the client. So what we can do is in page,
if we have a component here where we just gave it
a property of the startup Pokemon, that data will go across
from the server to the client and then that component could
then preload the store with that Pokemon. So that's what I'm going to do. I'm going to go create a preloader
component that will take in
Pokemon and set up the store is going to be a client side component. It's going to bring in the store, it's
going to bring the type of Pokemon and is going to bring in our setStartupPokemon
because that's what we use over here to set it up on the client. So basically name and do exactly this, but on the client,
let's define our component. It's going to take in Pokemon and it's
then going to set the Pokémon. So now as a React component
it has to return something. So is this going to return NULL. Now we only want to set this data once. So to do that I'm going to just use a reference to track it
and we'll say how we loaded when I started False. And then if we get run,
then loaded current is going to be true. And then
I go take this code, the store dispatch, and I'm going to drop it in to this
preloader. Okay, looks good. Let's go over here to our page, bring in our preload, our put this right up at the top here and give it the pokemon's with the data. Hit save. And let's see. Tada! Now we have it both on the server
when we need it in pure SSR and we have it on the client by channeling it
through the props of this preloader. So when it comes to preloading the store
state for your client,
this is a decent way to do that. Okay, now that we got this working, we actually want to go
and make this search work, right? We wanna be able to say, Bulb
make a request to our API off the client. So how do we do that? Well, we're going to use
the really nice React toolkit query. If you have React toolkit, there's
no reason not to use React Toolkit. Query is a fantastic resource. So do that. We're going to go create another slice, an API slice, and we’ll
call this one the Pokemon API and into
there I'm going to bring in Create API from Redux to get query
as well as fetch base query. That's how we go and set up where the base of our all our queries are
and of course the Pokemon type. Now we're going to call this reducer
because this is creating an API reducer for us.
We're going to call it the Pokemon API. So where are we getting our data? We're getting our data from localhost
3000 API. We're going to see that we have some tags. That tag is a type of Pokemon
and then we're going to say that we have an endpoint
and that endpoint is search and that call is search. So slash API slash search with the name
and you give it Q for query that's defined here,
that's the parameter type. And then the return type
is an array of Pokemon. And we are going to return this tag Pokemon with the search results. Now we need to bring it over into the store, so I'm going to go and bring in our
Pokemon API and I'm just going to add that as a reducer and I might save and see we get all right, it looks pretty good. And then I'll bring in some required
middleware. This is all documented
over on the RTK site. So let's hit our can see we go Cool. Awesome. Still works. Now if you are familiar with RTK query,
you might be asking yourself why I'm not using the slash
react bindings here because those actually make it
super easy to use this. You can just basically use
a bunch of hooks that it automatically creates
to go and get the data. But if we save this
and we hit Arc, what we see is this you get the create context issue. So what's happening is
that the server is bringing in the store because it needs the search reducer. Now, the store also includes this Pokemon API reducer which it's not using but still is referenced
and that Pokemon API reducer because we brought in
React is creating hooks. And you saw earlier
that any time you even think about hooks on the server,
you get this create context issue. So we can't use the really nice API hooks without either
creating another store, which would be a huge pain in the butt or well, in this case
we're just going to do it manually. So okay, we're going to take that out. Then we're going to go back over
to our search input and we're going to bring in our Search API because we want the Pokemon
API out of there and we're going to construct our own data
selector, which is going to get the result of the query
out of the Pokemon API. So Pokemon API is going to cache
a number of queries for us. Those are all going to be given
specific names, for example, search and then the search string
that we just used dot data
and that's going to be a type Pokémon. So let's bring in our Pokemon type. And now down in the Pokemon table,
we're going to say that if we have a search, which means that
the length is greater than zero, then we're going to use the data
that's come out of the Pokemon API, or if that doesn't exist yet, in that it's still in transit or in flight,
we'll just use an empty array. But in the case where we don't have a search,
what is used to start Pokémon because we already know
what the empty case is. So we'll use that for our start up. And now let's try it this out. Okay, Looks good. And we're doing the right thing. So now if we have a search,
we're showing the results of the search. But of course there are no results because we're not actually
initiating a Pokemon API search. So how do we do that? Well, what we can do is
we can say if we have a search, then we should initiate that API. And to do that
we would look for an effect. We want an effect to happen when we change search, which means
that we probably want to use useEffect. So we're going to use useEffect down here and we are going to depend on dispatch
which really never changes and search because that's going to change
every time we type a character. And then when we get a change to search,
we're going to dispatch the Pokemon API and point search
and we're going to initiate that search with the search parameter. Let's give it a try. All right, cool. That worked really well. So what do we learn? Well,
we learn how to use Redux on the server. We've learned how to get server
state to the client using a preloader. We've learned when to use stuff on the client
and when not to when it comes to hooks. And we also learned how to use
React toolkit query and avoid the issue
of bringing in those react bindings, which would cause an issue
with the server. But just go to the API endpoints directly. Well, I hope this helps you out
with your struggles with the NextJS 13 app directory and it's integration with state managers,
including of course Redux. If you have any comments or suggestions,
I would love to hear those in the comments right down below. Of course. In the meantime, if you like this video,
be sure to hit that like button. And if you really like the video, be sure to hit the subscribe button
and click on that bell and be notified the next time
a new Blue Collar Coder comes out.