Using Redux in Angular 2+ Apps | Mosh

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Honestly I'd prefer this tutorial to use ngrx/store

👍︎︎ 1 👤︎︎ u/i_spot_ads 📅︎︎ Jan 28 2017 🗫︎ replies
Captions
[Music] so what is Redux Redux is a library that helps you manage the state of your application and is something that you should use in medium to large single page applications with complex data flows so if you're building a simple application with simple data flow you don't necessarily need redux and in fact Redux can add extra unnecessary complexity your application so what do I mean by these large single page applications well in a typical angular app without the Redux archit without the Redux architecture you know that each component maintains the state and the logic behind the view this model aligns perfectly with the encapsulation principle of object-oriented programming however it can be a problem when you have multiple views that are working with the same piece of data and do not have a parent-child relationship in this situation we often have multiple copies of the same data that are independent of each other so whenever you update the model we need to do some extra work to keep the other views in sync for example think of Facebook on Facebook we have three views that represent the current state of users messages on the navigation bar we have this icon that shows the number of new messages and if we're on the messages page we have a view like this and irrespective of what page we are on we can also have multiple chat tabs on the bottom of the screen these are independent views that need to be in sync and what is important here is that they do not have a parent-child relationship so this navigation bar is not a parent or child of other views here if it was the passing data would be simple it will simply use the input properties of the child components to pass the data down the subtree but since these views are independent if you want to keep them in sync we have to do some extra work a common solution is to use events and sooner or later that will turn to an event spaghetti in a large code base we have events published all over the place and then to track what happens to the application state we have to jump all over the code to see what's going on the problem with this approach is that data can be updated in an unpredictable way when there is a bug we have to jump all over the code to figure out how the data is flowing and how the application state is updated in multiple places so it's unpredictable also adding a new feature becomes a challenge because once again we don't know what is the impact of this new feature on the application space if it's touching the same piece of data that is in different places that needs to be kept in sync again we have to do a lot of hard work so Facebook had this problem back in 2014 and that's why they introduced the flux architecture now Redux is a simplified and lightweight implementation of this architecture that provide a clean and elegant solution to this problem maintaining the application state in predictable way so there's no surprises now apart from this Redux provides a number of other benefits the first one is that it decouples your application from a presentation framework like angular so you can implement a big chunk of your application and its presentation logic using simple functions that are completely decoupled from angular or any other presentation frameworks and then you can decide if you want to use angular or maybe you want to use react so it allows you to postpone decisions about external libraries and frameworks which is one of the attributes of clean architecture as you might have heard from Uncle Bob the second benefit is that it makes it easier to test your application without marks spice and any other tricks that can make testing both complex and error prone because Redux is heavily based on functional programming so as you will see in this section we'll be writing simple functions take your state and return a new state that's all these functions are really easy to test and this means you can write your tests before your production code which basically means test-driven development or TDD the third benefit is that you can get some really cool tools as part of your development one such example is Redux developer tools extension that you can add to Chrome Firefox and other browsers it makes it incredibly easy to debug your application by allowing you to inspect the application state in such a way that we have never seen before this is actually one of the features that I was really impressed with and you're going to see that in this section and the last benefit is that redux makes it incredibly easy to implement features like undo and redo so if you need this functions in your application yes you can implement it without redux but using redux makes your life much easier now all these fancy benefits of course become really cut just like many other architectural patterns you're going to write a bit more code and you'll have more moving parts in your application so use redux only if you're building and medium to large single page application with complex views and data flows here are some scenarios you have independent copies of the same data in multiple places you have multiple views that need to work with the same data and be in sync the users can collaborate and work on the same piece of data so data can be changed by user a and at the same time user B can change the same data or data can be updated by multiple actors so it can be changed as a result of user actions and at the same time it may arrive from the server either for polling or push notifications so if you have these scenarios in your application it would potentially benefit from redux so remember when building a new app you don't need to automatically reach for redux you can always start simple and as your application grows then you can refactor existing components and use Redux to manage the application state in a predictable and deterministic way next we're going to look at the building blocks of redux in Redux we have three pieces the store actions and reducers let's explore these one by one the store is a single javascript object that contains the state of the application you can think of it as a local client-side database so here we can have properties like the list of messages number of new messages to be displayed on the navigation bar whether chat sounds are enabled and so on different views and components use different parts or different slices of the application state depending on their functionality and this also means if different components need to work with the same slice there is only one copy of that slice throughout the application so once a component modifies that slide the changes are immediately visible to other components we don't have multiple independent copies now the first question you might have is wouldn't it consume too much memory not really unless you're storing 10,000 or more objects in this store and then I would ask you why would you do that anyway so for the most part is ok to have a single object to store the application States the second piece is the actions actions are playing javascript objects that we present something that has happened in the application so semantically they're more like events if you have some background in CQRS architectural style you should know the difference between commands and events commands or actions represent something that should happen like posting a message whereas events indicate that something has happened like a message was posted actions in redux are semantically events here are a couple of examples when the user reads the message we can represent this event using an action like this as another example if the user posts a message we can have an action like this so these are simple data structures and don't have any logic and by convention we use a type property to specify the type of each action an action can have additional properties related to the event it just happens and the last piece reducer the reducer is a term that often confuses a lot of beginners to redux unfortunately the terms used in the redux library are not very helpful so actions are really events and reducers can be a little bit confusing to beginners now reducer is basically a function that specifies how the state changes in response to an action you can think of it as an action handler or an event handler that determines how this state is changed now what is critical here is that the reducer does not modify the state it only returns the new state and then the store will internally update the state so nowhere in the application we're going to directly modify the state this is the responsibility of the store it keeps the state and updates it whenever necessary so these are the building blocks of redux now it's reducers should be pure functions but what do I mean by pure well that's the topic for the next lecture so what is a pure function well a function is pure if we give it the same input we always get the same output no matter how many times we call that function so it shouldn't have any side effects let's take a look at a few examples so this function is impure because every time we call it its modifying its argument so if the value of the count property of the input is initially zero and we call this function ten times to increment it instead of getting one we get ten so in a pure function we should not mutate or modify any of the arguments here's another example in this function we're making back end calls by a disservice and this is an example of a side effect so every time we call this function our application state store it in a database on the server it's modified and here's the third example in this function we are updating the value of the count property based on a random number generated by the math class so with this function if they give it the same input we cannot ensure that we always get the same output the output is different every time because we are using an impure function so in a pure function we should not use math dot random or data now or any other functions that return a different value every time we color now let's take this first example and change it to a pure function so instead of incrementing this count property you return a new object with accounts property and the value of this count property would be the value of the original count plus 1 if we call this function 10 times and give it the same input we always get the same output so if count is initially 0 and we call this function 10 times we'll get 1 because this function is not modifying its argument so in redux our reducers should be pure functions now let's take this example and modify it a little bit so it looks like a reducer function in redux in redux user functions always take two arguments the current state and an action then based on the action type they return a new state so typically use a switch statement on the type property of the action and based on the value of the type property we return a new state so let's imagine action the type is increment then we return a new state with the updated property so you're not going to modify the original state pass the dysfunction now if you have never done functional programming before this concept is new and confusing to you I totally understand that so you might be asking what is the point of this why are we not allowed to mutate or modify the state you always have to return a new state well there are a number of benefits to this approach the first benefit is that pure functions are really easy to test imagine you want to write a test for this function you don't need any marks any spies or any other tricks you simply call this function give it an input and make an assertion about the output as simple as that the second benefit is that this approach makes it really easy to implement features like undo and redo because we always keep the previous state instead of modifying it and the third benefit is that it gives us a powerful tool which we call time travel debugging so using the tool that I will show you later in this section we can travel back in time and look at our application state as different actions are triggered in the application we can see how the application state is modified in every step and this makes it really easy to find bugs and fix them but once again it only makes sense if you're building a complex application with complex dataflow for a calculator application he doesn't need Redux but if you have complex views complex data structures and things have to be modified in different places then you can look at the application state and see exactly how its modified all right now let me show you how to add Redux to an angular app there are many implementations for Redux but the two common implementations are mg RX / Store and ng - - Redux these are the most popular ones and they're very very similar in terms of their API angel - Redux is built on top of the real Redux library and it's compatible with most of the redux ecosystem it adds bindings for angular 2 so you can easily connect your angular components with redux ng IX flash store on the other hand has done the routes of reimplemented the Redux pattern in an angular 2 and rx friendly way this means it's not compatible with other libraries build for redux so in this section I'm going to use ng 2 - redux but I wanted you to be aware of ng RX / store because there are a lot of blog posts and questions on Stack Overflow that are centered around this implementation alright now before we get started make sure you have the latest version of angular CLI so on my machine I'm using angular CLI version 1 beta 26 if yours is older simply do NPM install angular - CLI - JEE all right now I'm going to create a new folder Redux - demo going to this folder and run ng in it all right now if you look at package that JSON you'll notice that we're using angular 2 point 3 point 1 this is very important if you want to follow along with this lecture otherwise when you add Redux you're going to get an error in NPM because the latest version of redux is not compatible with older versions of angular so make sure you've got angular 2 point 3 point 1 or higher now back in terminal npm install redux so this is the main redux library for JavaScript it's got nothing to do with angular then we add n - 2 - redux which provides an angular module for dependency injection as well as some other helpers that we're going to use in this section so add this to the project now if for any reasons you're having difficulty creating a new angular project and adding these dependencies I've attached this project for you to this lecture so simply download it and then do NPM install and then NGS serve now if you head over to localhost port 4200 you get our familiar angular 2 app so now let's start implementing redux in this application first I'm going to go in the source folder under app add a new file store the TF here I'm going to export an interface called a app state so this interface determines the shape of our store for now we're going to leave it empty but as we go through this section we're going to add some properties to this interface so this interface will determine what properties we're going to have in our store now I'm also going to export a function which I call route reducer so we start with one reducer function here and as our application grows we can break down this function into smaller more maintainable functions each focusing on one domain in the application now as you saw in the last lecture each reducer takes two parameters the current state and an action and it returns a new state so for now I'm just going to return the state that we get here we are not going to implement a switch case here yet that's going to come in the next lecture so this is a very basic reducer it doesn't do anything all right save now let's go to app the module on the top we need to import a couple of types from ng to - Redux so import from ng to - redux first one is ng redux and the second is ng redux module now we need to import this module into our main module and that's use or dependency injection so ng Redux module now we want to create a constructor for app module this constructor should get an object called ng Redux which is of type ng Redux that we imported on the top now this type is generic so we need to specify a generic parameter here in angle brackets and what we pass here is the interface that we declared earlier so this interface determines the shape of our store so I'm going to go on the top import I app state and route reducer from current folder slash store now back in the constructor I'm going to use I app state as the generic argument for ng Redux and the final step we use this injury Dex object here and call configure store this is to initialize our store now the first argument to this method should be our route reducer so route reducer and the second argument is our initial store so I'm going to pass an empty JavaScript object this is our store object that will eventually get updated as we go through this section with this if you save the changes and get back to the browser the application should still work and we shouldn't have any errors in the console so let's double check that okay here's the console there is absolutely no errors perfect so we have successfully installed Redux in this project next we're going to work with action all right now let's see how we can use an action so here in app component template I'm going to add a button call it increment handle the colliculus and bind this to the increment method of our components I'm also going to add a counter here so when we click this button this counter is going to be incremented now let's go to add component stickler counter here and initialize it to zero I'm going to add the increment method so in a typical angular app this is how we implement this method you modify the state directly here however when using the Redux architecture we don't modify the state here instead with dispatch and action this action goes into the store the store knows our route reducer so it passes action to the route reducer and then the reducer looks at the action and based on the type of the action it will return a new state and then the store will update its state internally so let's see how we can implement this first I'm going to go on top of this file and import mg Redux from ng to - Redux so this is the primary type that the worked with in Redux applications now I'm going to create a constructor and inject ng Redux here ng Redux now you remember that this is a generic type so here we need to specify a generic argument which is I app state that's the interface that determines the shape of our store so I'm going to import I have state on the top like this constructor I'm going to apply the private modifier here so we can access this in the increment method now instead of modifying the state directly you're going to call this that injury ducks that's dispatch here we need to pass an action object and as you learn earlier an action is a simple object that has a type property so this is how we dispatch an action now some actions may carry extra data about the event that just happen for example if the user posted a message here you can have properties like body subject and so on but in this example we don't have to worry about that so delete every time we define a new action we need to go to our reducer and determine how the state will change in response to the action so let's go to the store here I'm going to add a switch statement on action that type and it is increment I'm going to return a new state with updated counter so currently it's not clear what is the type of this data object so I'm going to apply a type here this should be of type I app state so we get the current state of the store and then we return a new state so again I'm going to add a type here this function will return I AB state and now because we need to work with a counter we need to store its current value in the store so in I app state interface I'm going to declare a property counter of type number okay and now in response to the increment action I'm going to return a new object with counter set to state that counter which is the current value of the counter plus one so note that I'm not modifying the original state here I'm returning a new state and the final step earlier in app module here we passed the initial state of our store now we have a red underline here because our store now has a counter property that we have not initialized so back in app module I'm going to counter to zero so let's quickly review the steps and then I will show you how to improve this code in the app component we injected ng Redux in the constructor and in the increment method instead of modifying the state directly we dispatch an action then we went to our store we modified the route reducer and added support for the increment action then as part of this we also have to modify I app state so now we have this counter property and finally in the app module we modified this line here to set the initial state of our store now there are a couple of things we can improve in this code the first issue I see here is the use of this magic string in two different places we have uses in the app component and also in the store now the problem with this is that we have duplicated this in two different places and if we have a typo in the code our code is not going to work so it's better to extractives into one place define it as a constant so this way we won't have a type of problem and if you want to change this to something else in the future there is only one place we need to change so in the app folder I'm going to add a new file called actions and here I'm going to export a constant called increments and set it to increment now we can replace those two magic strings with this constant so first in the store on the top I'm going to import increment from actions and then I'm going to replace this magic string here increment now at the save time I'm going to copy this line and go to app component on the top paste it and once again replace this magic string with a constant that's the first improvement now the second improvement you notice that when we changed I app state here we had to go to the app module and modify this initial state object here so we are going back and forth between different files and this is really not good practice so let's go back to the store here I'm going to export a constant and call it initial State this is a type I app state and I'm going to set this so this object would counter set to zero now time we're going to modify the I app state interface we could immediately modify this initial State if necessary we don't have to jump back and forth between the store and the app module so now let's go to the app module and import initial state from the store and then replace this object here with initial State now if you run vacation at this point and click this button the counter is not incremented because we have only implemented the part for updating the state reading the state from the store is something else and that's what we're going to look at in the next lecture hey thank you for watching my youtube video my name is Maha Madani and I'm a full-stack developer applause I'd author and in getting the instructor with about 14 courses at the time of recording this video so I've got lots of courses on both front end and back end development including three sharp energy framework a selectman MVC angular architecture unit testing and so on this video watch is actually part of my angular course on udemy that you can get with a discount using the link in the video description and if you want to see my other courses simply head over to programming with mass comm slash courses you can also subscribe to my YouTube channel to get free videos every week have a great day and I'll be back show [Music]
Info
Channel: Programming with Mosh
Views: 120,863
Rating: undefined out of 5
Keywords: programming with mosh, code with mosh, angular 4, angular 2, redux tutorial, angular tutorial, angular redux, angular state management, learn redux
Id: UEcdQR-NoNA
Channel Id: undefined
Length: 29min 31sec (1771 seconds)
Published: Mon Jan 23 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.