Integrate Next.JS with Redux | How to use next-redux-wrapper (uses pages router)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey there welcome to the video and today we'll be discussing how you can integrate next year's with redux using a library called next redux wrapper now using redux with nexus is a little bit more complicated than using redux with react which i'm sure a lot of you must have already done and the main reason behind this is that next.js also enables it pages to be server side rendered a feature which is absent in react now the problem with server side rendered pages arises because whenever you request for such a page next.js newly builds that page on the server side and sends it back to the client browser but the problem with this flow is that the server is not aware of the client side redux store hence what it does is it creates a new store updates us with the new values and somehow we need to update these new store values that is present in the server side to the values that are present on the client side store or else the props that are fetched during the server call will be lost and for that we'll be modifying our main reducer a little bit so that we can handle such request and we are able to persist both the server side redux store and the client side redux store values in a way that we have a universal store so in this video we'll first be starting with the concept of a universal store and then we'll be moving on to the example project that i've prepared for you so let's get straight into it let's start by first discussing the concepts that are involved here so redux is a simple state management library now it can be used both in front-end and back-end frameworks but since most of the people have used it with react in react you only have client side redux stores but in next js you also have server side rendered pages so you can also fetch some data during server side rendering and you might want that data to reflect in the redux store on the client side but as you can see the problem here is that the server does not know about the values that are stored on the client redux store so what we do instead is we create a new server side redux store in such cases and update it with the fetch data and with the help of the library next redux wrapper we can utilize the hydrate action so this is an action type which is dispatch whenever there is a server side call and we need to look out for this particular action in our master reducer where we'll be handling the hydrate action and we'll apply the new store values to the client store as seen in this simple diagram here whenever a client requests for a server side rendered page server creates a new store it fetches the data updates that new store with the data and then it tries to apply this new data onto the client store and it's only in the case of ssr that we have to handle it differently and with the help of this hydrate action will be able to handle that particular case now you might ask why is a new store created on the server side why can't we just use the same store values the answer is very simple because there can be more than one client active at a given point of time and their data will get mixed up the other option is to persist all of the client store values somewhere in the back end which is just a very bad practice and isn't complete anti-patent which should never be followed because it's completely defeating the purpose of using redux with react-based libraries now for the next part of this video let me run you through the code base of our nexus application that will be using as an example for this video we'll start with the store folder so within the root directory there is a folder called store within which you'll find the main store.js and then there are two other folders called counter and users now these two folders represent the slices of data that are currently present within our redux store namely counter and users now you might ask what's a slice of data a slice is just a logically separated state value which is managed by a single reducer hence each of these two folders have a file called reducer.js let's quickly go over the slices and the reducer functions and we'll also see what kind of actions they are currently supporting now if you guys are not aware about what reducers are or what action objects are i highly recommend you to watch one of my previous videos around redux basics where i'm just talking about the bare bones redux library and there i'm teaching in a very easy way all the main parts that are present in a redux store the link to the video will be there in the description and will also show up on the top of the screen as a card moving on in our counter slice we have a reducer which only handles a single action called increment and a counter value itself only has a single key value pair called count which is initialized with zero and whenever there is an action of type increment in coming into our redux store we'll just simply increment this particular count value and then we have a function called increment counter which is used to create a action object of type increment so if you see this function is returning an object where the action type is increment now all of this is the standard boilerplate that you see within every redux project so i won't be wasting much time on it and quickly just running through things here our second slice of data is called users the user's reducer function is again handling only a single action of type add user and what this add event action is supposed to do is to just add the new user which will be present under the action object by the user key into our user's array so a user's array has been initialized as an array with two elements but in the future we want to expand on this particular user's rn we'll be adding more users to it and again in our action.js for users we have a user's action object which only has a single key value pair for add user action and add user function which unlike our previous counteraction function which was not taking any parameters since it didn't need one our user's action object does need a parameter which is the new username that's supposed to be added onto the user's list so along with the action type you also have a key value pair for adding a new user then moving on to our store.js file we are simply importing both the reducer functions of the two slices and then we're using the combine reduces function from the redux library to combine both the counter and user's reducers into a single reducer and then we're defining another function called init store which is just being used to initialize a final store and this function does nothing but just return this particular function called to create store now create store is the main function that is being exported from the redux core library which basically creates your redux store which holds the final state tree and we are also passing another argument with the function called to compose with dev tools this is just used to enable the chrome extension for redux and then we're simply passing this in its store function to create wrapper which is being imported from the next redux wrapper library now how to use create wrapper from next redux wrapper is something that i just followed from the official documentation itself so if you scroll to the usage part you'll find an example for implementing your code in plain javascript so here as you can see they are calling the create wrapper on top of the make store function this make store is synonymous to our init store and then as a next step what we need to do is import this particular redux wrapper in our underscore dot app.js file so in our pages section we have this underscore app.js file here we have imported our wrapper just as the documentation says and before exporting our main app component we need to wrap it around wrapper dot with redux function and in the last line here before exporting our main app functional component that we have created here we are wrapping it around with wrapper with redux by writing this much code we ensure that all of our pages are wrapped around with the redux wrapper now going to our actual pages that are present there are only two main pages in our application our index.js present at the root route of the application and then there is something called other.js i'll show you first what they look like on the browser so if we go to our main application at the root route the index page is present and then if we click on this navigate button here it takes us to the other page which is present at the other route so routing is something which is very simple in next year's whatever name of the file that's there becomes the actual route for the file in the address bar the main difference between the two files is that index.js is statically generated and by that what i mean is that the data fetching for this particular page is happening statically at the build time hence this is using the get static props function while on the other hand the other dot js page is a server side rendered page and hence we are exporting get server site props function now our main focus will be on the server side rendered page itself and if you see inside the get server site props function we're making a call to a fetch users api which is this end point available to us where according to the id that we provide it sends back the user's details so here we've written the code to fetch a random user anywhere from the id 1 to 10 and then dispatch store action to add this user onto the users list so here we should be able to see that particular name but as you can see if we refresh on the page nothing like that is happening and this is because the data fetch and the dispatch happened on the server side and right now we are not handling how the server side store values will be forwarded to the client store we were also dispatching an increment counter function and even that's not getting updated here so the counter is still zero if you want to talk about the actual contents of this page we are just reusing a component called page which is present under the components folder all it does is it calls to other components increment counter and users which are using use selector and use dispatch hooks from the react redux library to access the current state values and to dispatch actions again this is just the basics of how to use react with redux which i will not be going into detail in this video let's just straight away jump into how we can write our master reducer which handles our server side state updates i'll show you how the pages are working right now so if i give some new name it will add on to the list the counter will also update but once we navigate to the next page there is no new user fetched which was supposed to be fetched and even the counter was not incremented but if you notice in the redux dev tools here there was an action called next redux wrapper hydrate that was called when we jumped from the static page to the server side rendered page so if i just go back to the previous snapshot as you can see there is no difference when there should be so let's update our store file here to handle the action that we just saw and for that we need to import hydrate from next redux wrapper when i hover over it you can see that hydrate is just an alias for next redux wrapper height rate which is the same action name that we saw here in the dev tools so next redux wrapper hydrate is the same thing that we want to handle here so let's go ahead and write a code for the master reducer which will handle this particular action so we'll create a new function called master reducer which has access to state and action like any other reducer function inside this i want to handle the new action type hydrate and this action object will also have within its payload the new data that was fetched so here in the documentation you can see that the incoming state to the reducer represents the previous state and then action.payload has the server side store with the newly fetched data and the comments is mentioned that we're applying the delta from that to the client store so basically we're just hydrating the client store with our newly fetched server side store values we'll be doing something similar but it will be tailored to our use but let's also define what needs to happen if the action type is not hydrate in that case we just simply want to return the state as it is so whenever we are dealing with static rendering or client-side rendering this will be the case that gets executed so let's just copy this else statement and paste it here okay let's now actually implement our hydrate case we'll define something called next state where we'll copy all the previous state values but for a users list what we want to do is we want to keep the user's array values from both the server side and client side store so from both the state value and action dot payload and for that all i'm simply doing is creating a copy of action.payload.users and then state dot users spreading it in an array and then we're creating a set around the array because there can be repeating values i only want unique names to be present so i'm just wrapping it around a new set and then i am simply spreading the set itself this will allow me to persist both the client and server side values now what you just saw here might feel like an issue for a lot of people because every time you want to persist values you will have to write a separate case for it here in your master reducer if you're working with a very big project this master reducer might get really huge and it might not be maintainable anymore so do think about this problem before you want to go ahead with it and then we just simply want to return this next state in the case of height rate instead of the combined reducer we want to pass in the master reducer let's save our changes and see how our application looks like as of now so on our index page let's try adding a new user and then we'll navigate to our server side rendered page where as you can see there was a new entry emma wong added let's add another name here let's navigate back to our index page and back to our other page we have another random name added to a list and if you see in the redux dev tools under the different section you can clearly see that our next redux wrapper per height rate action object is introducing changes to our client side store we also wanted our counter to increment by one whenever we go to the server side rendered page so let's write the case for that too so here we just set that to the counter value of the current state add the counter value that is coming from the server counter which will only be one in our case so let's save our changes see if the counter is also getting updated we'll start fresh from the index page let's add to the counter just notice that the counter value is 3 when we navigate it should become 4 it's becoming 4 and we're also getting a random name added to the list let's navigate back the value is becoming 5. let's navigate back to the other page and it got incremented again and another random name was added so this is how by wrapping your combined reducer with a master reducer that is handling your hydrate case in xjs you can bridge the gap between your client side redux store and server side redux store and this gives you an illusion that you're working with the universal reducer which works on both the client and server side i took this specific example keeping in mind that we cover simple state values like a counter which only has a numeric value count and then a more complex data structure where our state is an array called users now whenever you're working with redux it really helps in knowing how to create deep and shallow copies of objects and arrays i've made a lot of videos about it you can go check them out but here just by using the principle of destructuring we were able to create a set of unique users and display them on the screen for the values that are not updated during server side render you don't have to write a separate case for them like this they will simply be copied by spreading the state so you don't have to write them separately like counter and users for example let's say in our counter store value there was something else called logged in by default its value is false and since this logged in state is not getting mutated by any of these dispatch actions here in the get server side props i don't have to handle it separately here in this line itself it will be copied so redux integration with nexus is working perfectly now i'll be uploading the source code to github and putting the link down in the description please feel free to clone this application and use it as a starting point for your nexus application which is using redux i hope this video really helped you guys in understanding the concepts that went behind in supporting redux with next js and if you have any doubts please mention them in the comment section down below i try to reply to all of the comments as quickly as possible like this video if it helped you guys in any way and also subscribe to the channel for more future content i upload new videos every week and that's all i had and i'll see you guys in the next one
Info
Channel: Mayank Srivastava
Views: 21,851
Rating: undefined out of 5
Keywords: redux, nextjs, redux with nextjs, redux with next js, next js and redux, nextjs tutorial, learn nextjs, next 12 redux, nextjs state, next state management, state mangement, next redux wrapper, next-redux-wrapper, npm redux wrapper, nextjs redux wrapper, universal reduxer, ssr, server side rendering, server side redux
Id: 1EaRWZjTwYM
Channel Id: undefined
Length: 17min 58sec (1078 seconds)
Published: Thu Apr 07 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.