Intro to Managing React Application State With Flux and Redux

Let's learn about Flux and Redux.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the The newline Guide to React Native for JavaScript Developers using TypeScript course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to The newline Guide to React Native for JavaScript Developers using TypeScript, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course The newline Guide to React Native for JavaScript Developers using TypeScript
  • [00:00 - 00:19] So far in this module, we have looked at how we can manage state at a component level, be it a class component or a functional component. Then we also looked at how React's context API helps avoid pro-drilling and it can allow us to access a particular context in the end-level children.

    [00:20 - 00:32] Next let's look at state management at an application level. For this we're going to look at Redux.

    [00:33 - 00:48] What Redux does is it basically implements the flux architecture which was made popular by Facebook and it's a very popular way of managing states in application. The primary concept of flux application is that it implements a unidirectional data flow.

    [00:49 - 01:01] What that means is as previously we might have seen in Angular and other applications which allow parent and children both to change the state of application by doing a two-way binding. Flux doesn't do that.

    [01:02 - 01:15] What flux says is that we need to have a one-way data binding. Now the three major parts of a flux application are the dispatcher, the store and the view.

    [01:16 - 01:39] Let's see how that works. Let's say that a view has fired an action so it will go to the dispatcher and the dispatcher will then invoke the callback that the stores have registered with them and we can have multiple stores and the stores will respond with whichever actions that are relevant to them.

    [01:40 - 01:52] Let's say that we have different stores, one for analytics, one for logging, one for card, one for homepage. So whichever action is relevant to them, what they will do is they'll listen to those actions.

    [01:53 - 02:12] They'll update the state of the application and they'll provide a change event which is then listened by the views which act as controller views over here. And what the views will do is they'll pull the new state of the application and then call us set state on them and update themselves.

    [02:13 - 02:42] So that sounds complicated but once we look at the actual implementation, you 'll find that it's quite simple and this allows us to track every action that a particular application is going to perform and we can tie every action to the change in state. So as it might be implied debugging and troubleshooting becomes very, very easy as every change in state is registered with an action that performed it.

    [02:43 - 03:06] Now as the application grows, the dispatcher actually becomes very, very helpful as it can manage the dependencies between the different stores that we have. And let's say we want to make the callbacks in a certain order, the dispatcher can help us achieve that.

    [03:07 - 03:19] So what Redux does is it basically implements the flux architecture. It was built by Dan Abramov and Andrew Clark and it's almost a de facto choice for state management and react applications.

    [03:20 - 03:32] So what it does is it stores the app state as a poujo that is a plain old JavaScript object. So if we go to any application that implements Redux, we can read the entire state as a simple JSON object.

    [03:33 - 03:52] And this can be an example of that we have a state and we have these different stores or users store and an app store and they have their own data attached to it. Another important thing is that the state is read only and whenever an update is done to it, it can be only done through a particular action.

    [03:53 - 03:56] Now what are actions? Actions basically have a type.

    [03:57 - 04:24] So what they will be is a type an update filter or an add to card and they have a data attached to it. How this helps is whenever the store changes or updates, we have a particular action tied to it and we know what particular action was performed either by user or by the application and what was the data passed to it and how that led to the new state of the application.

    [04:25 - 04:35] So the users are what helped tie the states and action together. Making in simple terms, it's just a function that takes the state and the action and returns the new state.

    [04:36 - 04:41] But we can do all sorts of logic in between. Like let's say it's something as simple as add to card.

    [04:42 - 04:57] What we can do is we can take the previous state and then add the new item that has been added to the card and return the new state or it can be more complex. Like let's say we do a toggle filter and we want to execute some business logic based on that.

    [04:58 - 04:59] We can do that. So that's mostly it.

    [05:00 - 05:14] These are the terms that we're going to interact when we talk about state management using Redux. Just a simple thing to remember that it's a unidational data flow and everything that we do in the application, we do it through a certain action.

    [05:15 - 05:19] So a view fires an action. It calls a dispatcher and then the dispatcher calls the relevance stores.

    [05:20 - 05:36] It has relevance stores registered with it and they can listen to all those actions and then update the state and the store after updating the state gives a change event which is listened to by the views. So let's see that in action.

    [05:37 - 05:49] We'll be using the reactative debugger to view the console log. What this helps us to is it helps us visualize how the store of the application changes.

    [05:50 - 06:13] So if you see for this particular state, we only have the apps splash speed launched and this is the initial state of the application. We have an app store and it has is loading false and as soon as an action of types flash launched was dispatched, the state was updated from is loading true to is loading false.

    [06:14 - 06:20] So let's go ahead and see that. So first let's look at how we register the store.

    [06:21 - 06:31] We already have that built in into this boilerplate code we added react redux and redux thunk for that. So we'll be using thunks for side effect handling.

    [06:32 - 06:41] So what that means is that they're going to act as our registration for disp atches. Next we go to the application store.

    [06:42 - 06:59] So we go to shared redux and we go to store and that's how we register it. We import create store from redux and we just say that store equals create store and we pass the reducers to it, which we will be defining for this particular application.

    [07:00 - 07:21] So right now we only have a single reducer that is app and it has only one type of action that is flash launched and we pass the reducers and then we apply the different middleware to it. So what examples of a middleware can be loggers and analytics which can all listen to these different actions that are performed by the application and do something based on that.

    [07:22 - 07:41] Like let's say that we want to track how many times this splash screen was shown or add to cart was clicked. They can listen to the actions for that and then fire their own pixels for analytics and for logger we can have actions for errors and network failures and they can log those errors.

    [07:42 - 07:57] We are using redux logger so that we can get this kind of a view while in development mode. So we wrap the redux logger inside this step block and after all the middleware is right now we have only added thunk middleware but let's say that we wanted to add more of them.

    [07:58 - 08:08] We should add all of that and the logger middleware should be the last one to be added. Otherwise it may not be able to show the difference between the initial state and the final state correctly.

    [08:09 - 08:26] Once we have our store setup we can create our thunks. So right now we have only one thunk declared that is for the splash screen that we saw and what it basically does is it just dispatches the splash launched type of action.

    [08:27 - 08:48] So if you look at this this is action types dot splash dot splash launched. For this one it's a simple implementation but generally any business logic that we want to do like make a network call when we load the application we have the user token we want to fetch the data for that we would do something like this in the respective thunk.

    [08:49 - 09:04] Then we have the reducers. So right now we have only one reducer and reducers basically have an initial state that is declared for them and they listen to the different actions that are performed and return the new state of the application.

    [09:05 - 09:25] Like initially we had state with is loading as true and once the splash launch action was fired we return the new state as whatever the initial state is plus is loading as false as what we saw in the console over here. So that is the entire setup.

    [09:26 - 09:32] Now let's go ahead and implement one of these. Let's do an active card.

    [09:33 - 09:54] So what we'll do is let's add a button on the home page which will allow us to add items to a card and we'll use this entire flow to maintain the application state for the item that are in the cart and update the count on the bottom index. So the first thing we'll do is let's declare an action for it.

    [09:55 - 09:59] This is app. Let's declare one for cart.

    [10:00 - 10:28] So we'll say cart and we'll say add to cart and let's also declare the type for it. It's advisable to use variable names rather than string constants across the application.

    [10:29 - 10:43] So this file basically helps us do that and we'll say card dot add to cart. So we have our action defined.

    [10:44 - 11:14] Now next let's create a thunk for that. So we'll have a cart thunk and we will say add items to cart and we'll add it from cart actions and we'll fire that.

    [11:15 - 11:21] Okay so we also need to pass what we want to add to cart. So let's also go ahead and do that.

    [11:22 - 11:44] We'll have some kind of a data and let's declare that as any for now and we'll also say that this is the data that we need to add to cart or we can say item as data. Now we need to pass that particular item.

    [11:45 - 11:57] We'll say item any and we'll pass that. So that is quite simple.

    [11:58 - 12:15] We have registered a middleware and all we need to do is we need to now call it from the UI. But before we do that let's also declare the reducer for that that will basically help us tie the action and the thunk to update the state.

    [12:16 - 12:55] We'll go to reducers and let's create a new one. We'll say cart and we have an initial state of card as an empty array and we'll listen to the action type from cart and what we'll basically do is return the initial state plus we will say cart as and action dot we had item.

    [12:56 - 13:15] So that should update the card. So let's save it and we need to add it to the combined reducers.

    [13:16 - 13:35] So with that we have registered our new store for cart and if we look at the console we should be able to see that. So let's look at the state now we have app is loading true and cart as an empty array and after the splash launch is loading is false and cart as a cart within.

    [13:36 - 13:47] Okay we have a cart and a cart so let's do items. So we can probably do this.

    [13:48 - 14:03] Items and we'll say. Yeah okay so next let's go to home page and let's add a button.

    [14:04 - 14:38] We'll have an add to cart button but let's try and market. So we'll say component home and let's pick one of these buttons and say that we want to add to cart.

    [14:39 - 14:52] If we have our button now we've already declared our reducers and actions and the thunk. Next one we need to do is we need to call the thunk from our views.

    [14:53 - 15:19] So into dispatch and action creator which is basically a thunk from our view will dispatch this cards add item to card from our view for that we need to register this with our home component. So let's go into that and we will say.

    [15:20 - 15:45] Let's do that any for now and we'll dispatch. So this function automatically gets a dispatch as a param and it is of the type thunk dispatch.

    [15:46 - 16:27] So let's call that and we'll call add items to cart from our cart action creator and we need to pass the param to it. Okay let's save that and now we should have this particular method available as props to our component.

    [16:28 - 17:01] Let's go to home page and let's declare that as props we will say add items to cart. And it is of type.

    [17:02 - 17:26] So this is the type that is of dispatch so you just declare that here and now we can call it from our home page. So let's go to the add to cart button and we will say this dot add item to cart .

    [17:27 - 17:48] Let's declare that add item to cart. And let's just call that and it requires the data.

    [17:49 - 17:58] Let's put anything for now. So we'll say sku some rescue.

    [17:59 - 18:09] So let's go to our add to cart button and let's see what happens to the state once we click it. That's our previous state.

    [18:10 - 18:29] We have got with atoms is nothing and then an action was fired. The action was of type at to cart and we pass some data to it and once it went through the reducer so if you go back to the reducer what we do is we take the initial state and we take whatever items are there and then we add the new item to it.

    [18:30 - 18:49] So let's go ahead and check that this is a new state item and cart and we have the new items and inside this we have the rescue that we pass to it. So we can click that again and now if we check again our cart items as two entries into it.

    [18:50 - 19:24] So as we can see every action that we perform in the application maybe it was initiated by a user or maybe it isn't something like a scroll or if we move to a different page and we want to track different page views we can fire actions for that and we can very clearly see what was the state before that action was fired and what happened after that action was fired. So if you want to troubleshoot something for an unexpected value or what changed the state this particular pattern makes it very very easy to troubleshoot and debug all of that.

    [19:25 - 21:11] So next let's try and display that to the cart icon that we have what we can do is we can do that as a part of thunk so we can do it just after this we'll just say navigation dot merge options and we'll pass the component ID what we want to do is we want to update the icon for the cart screen so we'll say screens dot cart bottom tab and in badge we can pass the new value to it. So we can get the value is we can get it from our store we'll say const store equals store dot get state dot cart and we should have it in store dot okay we're not getting that because we have not really declared type for this and let's also do that and the best place for that would be inside the combined reducers what we can do is we can declare all the different types over here and then use them across the application we'll say next port interface and let's call it root state of the application and we'll say app as app state and cart as cart state and we can declare these types.

    [21:12 - 23:14] So let's create that folder new folder types stores and let's declare app.ts and we'll say export interface app state and currently we only have s loading which is of type boolean. So and let's also declare the cart state and in cart state what we would have is item there's an array for now so cart state items and we'll have area of item let's also declare the item and for now let's have sku as string so that should sort us also let's change the name for app state it seems to be clashing with one from react native so we'll say application state just to make it different and we'll say application state and similarly we'll also import the cart state.

    [23:15 - 30:36] So let's also pass that to combined reducers root state and we also need to pass the type of actions that we can perform so let's also declare that so we'll say type new file I action and let's just declare generic action what it can have we'll say export interface I action of type t and we'll say that we'll have a type string and data of type t and data is not compulsory and I think that should be enough for now let's also pass that I action and then any next list also mark these as their types application state and similarly for cart we can have cart state and it has the items okay now we should be good to import the items from this cart and we should get that over here now if we do store dot items we get that so let's pass that over here so we'll say store dot items dot length and badge requires a string we'll do this and let's save it and now let's check that on the UI initially we don't have anything then we do an add to card and we get one we do another add to cart and we get to so that's how we'll maintain the application state let's go back and have an overview what we did was we had a view that was our home page and we fired an action from the view so let's go to the home page and we went there and we said that we want to dispatch this particular action that is called add item to card we went there and we dispatch this and inside this we dispatch the action add to cart with the data that we got and that action and this action creator was switched together by the reducer and what the reducer did was it was basically listening for the add to card action and it concatenated the new item to the existing items in the card so that's where it updated the store and returned it and once that was done it fired an event which was listened by the UI in this case we did not really display it to the UI but we can also do that what we did was in the action creator we updated the item count in the card icon but let's say that we want to you display that to the UI and update it and how we do that is we go to the home component and then in index we have this method that is called maps date to props what this does is it allows us to map the application state and pass it as a prop to the component so let's do that we want the application 's cart store in the UI let's pass that so we'll say card and we'll say state dot card and it gets state as its parameter and this will be of the type root state so now we have cart as a prop on the UI and if you want to display it somewhere we can do that so let's display it just beside this and we will say card and we need to declare this as props so what we can also do is we can actually take these props and declare them in the index file because that's where they are actually required what this map this time to prop returns is it returns a partial and takes props as types so we can do that and let's declare cart as cart state that makes it cleaner import props from and we have that next let's display it I'll just try and display it with the button and we'll say card dot items dot length let's save it so it has to and I click it it becomes three if you want to access the state on the UI we can do it in this way and as we can see the state of the application is managed by the actions that we perform so that makes it very very easy to troubleshoot and this also scales really well for large applications where we have multiple stores and multiple developers working on the same code base it's easy to mess up the state of the application though with this kind of an implementation troubleshooting the issues should be fairly straightforward so to recap in the first module we saw managing a state at a component level be it a functional component or class component then we saw how react context API is help us avoid prop drilling and although they are useful we should use them sparingly as they can make the component tied to a particular context and make them less reusable and then we saw the flux architecture for managing state in the react application and we saw how readers does it now there are also other libraries and mobx is also a popular one and that's all for this module I'll see you in the next one