Integrate Redux Toolkit with Next.JS and support server-side prop fetch (using `pages` router)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to the video and today we'll be discussing how you can integrate redux toolkit with your next js application this topic was highly requested on one of my previous videos where i discuss how to integrate bare bones redux with next js so here we'll be using the same example project but this time we'll be integrating it with redux toolkit instead of redux and we'll also be discussing the main problem that comes in when we integrate any kind of state management library with nexus because next js also introduces server side rendering to start with things i'll be running you guys through the code that's present in our starter project the link to the project will be there in the description so you guys can go ahead and clone it and follow along as we go through this tutorial i'll also be uploading the finished project at the end so you guys can clone that and use that as a sample project for any of your future applications in nexus which are using redux toolkit so without any further ado let's get straight into it so here we are on vs code where we have a very basic nexus application our application only has two pages as of now so under the pages folder you have add the root route your index file and then another file called other.js and both of them are pretty simple if you look at them they're just rendering a page component that is present under the components folder and we're passing the title of the page and the hyperlink if you see the page component itself it just renders the title as an h1 using props.title and then it's rendering two more components called users and ad count so here on the root route you have your index page which is rendering this page component with a title is index page and then you have this users component which allows you to enter a username and when you click on add it adds it to the users list down below and then the next thing is the counts component which enables you to add to the counter on the click of this button then at the bottom you have a nav component which only contains a next link and it points to the route which we send from our next year's pages as a property so things are pretty simple as of now for state management we're just using simple state and we will be changing all of this very soon where we'll be using redux toolkit to implement our state management so let's see what the application behaves as of now we were able to add the name and also increment the counter but once we navigate you'll notice that our values are not persisted this is exactly a use case where something like redux toolkit is needed because we want to persist our state values throughout components without passing them around as props so let's go ahead and start integrating our current project with redux toolkit so let's start by installing redux toolkit first i'll be running the npm install command so here i'll stop the development server run our npm install command and wait for the dependencies to be installed the next up will be creating two slices using the create slice function that's available from redux toolkit let's look at the javascript version of the example here to the create slice function we pass the object as a parameter which has three key value pairs the first one is the name of the slice itself then we're passing the initial state for the given reducer and then we write our actual reducer which is handling all the incoming actions and how you define actions is pretty simple here you just need to create a new function by the name of the action so here the action name is increment it has access to the state and action parameters and then you can just simply mutate the state value as per your action needs now one thing to remember here is that redux toolkit uses the immer library under its hood which allows you to directly mutate your state values so you don't have to copy them first and then mutate them which is a big advantage and allows you to write a lot less code now if you want to draw a direct comparison with how you do things in bare bones redux we always used to create a reducer function which used to take in the initial state and the action as a parameter and depending on the type of action it used to mutate the state so here in create slice we're doing something very similar under the hood create slice uses create action and create reducer as the documentation here says and think of it as an advanced way of writing your reducer where you don't have to write so much boilerplate for your actions and action creators all of that can be exported from the output of this function itself so here if you see we are able to export the actions and the reducer from counter slice variable itself so you don't have to create a separate action file which has all of your action types and action creators all of that can be done by using this one simple create slice function that's why a lot of people prefer using redux toolkit over redux because it reduces a lot of boilerplate so let's go ahead and create our first counter slice which will be very similar to the example that's given here in the documentation so here in vs code under the store directory will be creating a new file called counter slice we'll import create slice function from redux toolkit and as we just saw this function accepts an initial state an object full of reducer functions and a slice name to generate the action creators and action types that correspond to the provided reducers so next let's define our initial state object which is currently only holding a single key value pair count and is initialized with the value 0. then let's call the create slice function we'll store it in a variable called counter slice and we'll also be exporting this particular slice from the file now as we saw in the documentation the object that we passed to create slice needs a name property we'll keep the name as counter then we'll pass the initial state that we just created on top here and then we need to define the reducers for this particular slice of data in our store so we'll start writing our reducers here for now i just want a single increment action to be present for the given slice and for that i'll just create an action called increment and the only thing the reducer needs to do is increment the state count value so the updated state count will be state dot count plus 1 and that's basically it it's a very simple reducer but let's also go ahead and export the actions and action creators from the current file and for that i'll just say export const the action increment from counter slice not actions so all the actions will be present under the actions key for every slice so for example here i'm destructuring the action increment from counter slice not actions in the end let's just define a default export for this particular file which will be the counter slice dot reducer and this is what we'll be exporting and passing to the combine reducer function after we're done defining both of our slices next up let's go ahead and quickly create a user slice we'll again import create slice from redux toolkit and we'll create our initial state value which currently contains a user's key initialized by an empty array this array is supposed to store all of these names that we are adding using this new user input so this user list that you see right here will be persisted in our users array then we'll call the create slice function and store its response in a variable called user slice and again in the parameter object we need to give the name of the slice which is users the initial state and then the actual reducer function here i'll be creating just a single action called add user but unlike a previous counter slice our add user action will have a use for the dispatched action value so whenever an add user is dispatched the updated state users will be an array which will contain all the previous state user values so we'll use the spread operator to copy all the users present from a previous state and then in the array we'll also add the new user that will be present under action.payload now remember whatever data that you pass while dispatching an action in redux toolkit will be present under action.payload and we'll see how that works just in a few minutes next up define our default export which will be the user slice reducer and also export the action add user from the actions object at this point of time we're done defining the reducers by using create slice let's create our main store by adding a file that we'll call store.js under the store directory here we'll import combine reduces and configure store functions from redux toolkit combine reducers is used to combine two or more separate reducers into a single parent reducer and how it works is pretty simple so we have used the import statements here to import the reducers from the slices that we just created and then we'll be calling the combine reducers function which takes an object as a parameter where you just need to pass the reducers as the key value pairs next up we'll be defining a function called make store which is calling this configure store function and the parameter that it takes is an object to which we'll be passing our main reducer which we saved as combined reducer this object that we pass as a parameter requires our main reducer to be present under the key reducer so we'll just add that key in front of it now before moving forward we want to install two more packages called react redux and next redux wrapper so in the command line i'll say npm install react redux and next redux wrapper now react redux is just a library which enables you to use the dispatch and get state value functions inside your react components so using this library will be able to access our state values and mutate them on the client side and then we have something called next redux wrapper as the name suggests this acts as a wrapper around our main redux store so that it's next js friendly so let's go ahead and install these two dependencies from the library next redux wrapper we want to import something called create wrapper and to use create wrapper all we need to do is call this particular function and pass our make store function to it as a parameter we are storing the result in a variable called wrapper to integrate it with the rest of the pages that are there in the application we'll be importing this wrapper in our underscore app.js file now our underscore app.js file is a very important file in nextgs it enables us to initialize all the other pages that will be present in the application so here we'll first import the wrapper from our store file and instead of just exporting our main app component will pass this app component to wrapper dot with redux higher order component this higher order component enables us to wrap all of our page components with redux and we'll see how this is helpful by making our other dot js page a server side rendered page so a server-side rendered page requires you to export a function called get server side props and within this function data data is supposed to be fetched during the server side build is supposed to be called here we'll be calling an api endpoint which is available to us on the web what this endpoint does is it lets us pass a user id and according to that user id the details of that user is fetched now what i've done here is instead of passing a single id i'm passing a random id every time this particular getserversideprops function is called and since it's a fetch call we also have to do a dot json over the response to parse the incoming stream as json after fetching the data i want to update this data in our store by using store.dispatch so i'm dispatching the action add user for that let's first import the add user action from our user slice so we've imported it here we're calling store.dispatch on add user but if you notice we don't have access to store yet and this is where your wrapper comes in handy so we'll import the nexus wrapper for redux here into our page and then all we need to do is wrap our get server site props function with another function that's provided by our wrapper so here we have successfully wrapped our previous implementation by wrapper.getserversideprops now using this we'll have access to our store inside our function while we are fetching props so we'll be able to successfully dispatch actions during the server build now let's go ahead and also import the increment action so what i'd like to do is every time this page is requested i'd also like the counter to increment by one so let's also dispatch the increment action object here and since we are calling an api call which is asynchronous we'll also have to make our fetch props function async now let's quickly go ahead and also integrate react redux in our components under the components folder which are using use state as of now instead of use date i'd like to use the store values and when user clicks on increment instead of updating the state here that we have defined using u-state i'd like to dispatch an action so i'll import the use selector and use dispatch hooks from react redux library and i'll also import the increment action creator from the counter slice we'll instantiate use dispatch and instead of using use date we'll just use use selector like this to fetch the current counter value and instead of using set counter now all we need to do is dispatch the increment action object so this will be replaced by a dispatch call similarly let's also change our users component so here again we'll import the you selected and use dispatch hooks and also the add user action creator instead of using use date for storing the users list we'll be using the state returned from u selector we'll also instantiate the use dispatch hook and instead of using set users we'll just dispatch and add user action object let's see if any other changes are needed i think this is it let's save everything and run our development server so we'll hit npm run dev our server is up let's request for the index page we should be able to add user and if you see in the dev tools an add user action was dispatched and we should also be able to increment the counter so you should see the increment action being called thrice now while navigating to the other page we should see a random user getting added and also the incrementation of the counter by one so let's see if that's happening so when we navigated to the page no new user was added and the counter also remain same now why did this happen let's check our dev tools again we don't see any additional actions but instead we see something called next redux rapper hydrate being dispatched now this is the important bit this is where the concept of a universal store comes in the problem here is that whenever you request for a server side rendered page the server is not aware of the store values that are currently present on the client side so right now if you see on the dev tools the server is unaware of these state values so what the server did was it created a new store updated that new store with the fetched values there is no bridging between the new server side store and this current client-side store so your data that you fetched was lost in the middle we can prove this by just turning on the logs for our store that we created here using create wrapper we'll pass another argument which is an object having a key value pair called debug with the value true we'll save this we'll refresh the page and see what's there on the server logs now this time you'll notice because we turned on the debug logs you were able to see what all is happening so here on the first line you are able to see the new store that was created by the get props function where the store has all the initial values that's what's being reflected here and then the second line you seeing the props that are fetched on the server side so our props were actually fetched the api call happened a new random user was fetched and our account was also incremented but we were not able to see these changes on our client side so next up what we need to do is we need to update a client-side store with this newly fetched data and this can be achieved by taking the help of the action next redux wrapper hydrate that was dispatched here this action is fetched whenever we request for a server side rendered page and in the payload of this particular action you will get your newly fetched data so what we need to do is create a master reducer which handles this particular action and using that reducer will be able to create a universal reducer which can take care of both our client side and server side store as a single universal store now explain the theory and the concepts that go behind this in detail in my previous video where i discussed how to integrate next years with bare bones redux library in the first five or six minutes of the video i dive in the details of how things are happening when you're dealing with server side rendering in xjs and how to overcome the challenge you face while using ssr with redux so i'll put a link to that video in the description it will also appear as a card on the top of the screen do check out that video too i think it will really help you guys so to get moving with things let's create a new master reducer and the action that we need to look forward to that can be imported from the next redux rapper library itself if you hover over this you'll see that it's just an alias for the actual action that we just saw in the dev tools so here let's create a master reducer this reducer will specifically handle the hydrate action object so if the action type is hydrate then we'll do certain operations but let's write the else case first if hydrate is not dispatched all we need to do is simply return the state as it is so in the else statement here i'm just returning the combined reducer that we created previously on line 6 as it is but let's focus on what needs to happen in the handling of the hydrate action here i'll create a new state called date now remember the incoming state to this master reducer will have all of the previous state values so we'll first copy all of those values by using the spread operator but after this we'll also have to update each of these state slices that were updated during server side rendering separately so if we go to our other.js page inside a get server site props function we're dispatching two actions which are updating the users and the count state values so we need to handle them separately here by specifically mentioning how they should be handled now remember the data that is fetched that you can see in the logs here is present under the action dot payload so for our counter we can simply say that the count value inside the counter slice should be the current count value plus the value that is present inside action dot payload's count value so i'm trying to access this particular value here to our previous count value we're just adding on to the new count value that was updated during the server side fetch similarly with a user slice there is an array called users present inside it what we're doing here we're copying all the previous users and also the new users that were fetched using the spread operator so again the new users are present under action.payload.users.users and once we have written the code to handle all the changes that are happening during server side data fetch we'll just return this next state which has all our updated state values and instead of our combined reducer we'll be passing the master reducer inside the configure store function let's save everything go back to our application let's first go to the index page here we'll add a new user increment the value now what should happen when we navigate to the other page a new user should get added and also this value should increment to 5 so let's hit on navigate and as you can see so a new user was added and also a value got incremented we have successfully integrated redux toolkit with next.js while enabling ssr we can make some changes here again to the store navigate back to our index page and then back to our other page again a new user was added and the value got incremented to it and again in our dev tools you can track the difference that was added on to our current state under the diff tab so here you can see that the value clearly got incremented and also a new user was added and this is happening in every such hydrate action so with the help of this height rate action and the master reducer which is handling that hydrate action you were able to successfully persist state values across all of your pages even though some of them might be server side rendered now one thing to remember here in the master reducer is you only have to handle a case for a particular state separately only if it is getting mutated on the server side so let's say in our other.js file we never dispatched an action to increment the count value hence in our store we can simply remove these lines which are updating the count value and that was the last thing that i wanted to discuss thanks for watching this video and if you've come so far please hit the like button if this video helped you in any way and also subscribe to the channel because i post new videos every week
Info
Channel: Mayank Srivastava
Views: 32,737
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, redux toolkit, redux-toolkit, @redux/toolkit, nextjs with redux toolkit, next.js with redux toolkit, redux toolkit tutorial
Id: bpbLq6NxIm8
Channel Id: undefined
Length: 23min 2sec (1382 seconds)
Published: Fri Apr 15 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.