Aspen Payton is a Senior Analyst/Programmer at Mayo Clinic working in web development. Previous to her current position, she spent nineteen years as a software engineer at IBM. She is also an inventor with 31 granted patents or applications.View the profile
About the talk
This is a hands-on workshop that teaches participants how to structure an Angular application to use NgRx for state management. When I set out to learn NgRx a year ago, I found a lot of high level discussion of the Redux pattern and a variety of very specific code examples, but struggled to find education that laid out the pattern from beginning to end with fully functional examples. That is what I intend to provide with this workshop.
We will being with a starter project and existing HTML. We will set up state for the application, walk through creating a basic action and reducer, wire up the action and reducer in our app, and dispatch the action from a component so we can see it working in the app. From here, we can walk through the pattern again introducing additional complexity by passing a payload into an action and creating an action with an effect. Participants will end the workshop with a simple, but fully functional, application using NgRx.
Starter project: https://stackblitz.com/github/apaytonmn/bananaapp
Final version with comments explaining the code:
Follow us on twitter https://twitter.com/ngconf
Official Website: https://www.ng-conf.org/
So just some set some expectations hear my slides are available at the first link here. There's a reference to the starter project. You are all in this life as well. I'm we're going to be doing codeine along the way here and I'm like, the last session that I think was in here at my intention is not to talk a little bit and then set you loose on an exercise. I'm going to be codeine along with you guys. So if you have the slides, it might be a little bit easier for you to have a closer view of the code that we're going to be riding my intent is for you to ride along
with me. But if you just want to cut and paste it out of the out of the Flies, I mean, that's your your choice. I always feel that I learned better by doing. So one caution. If you do copy and paste out of the slides, I notice on my own when I was just doing some trial runs that some of the single apostrophes or the quotes in the slides are a little wonky. So if you copy and paste into the code and you get a a string error Some sort you might need to replace those single quotes within the code. I have some checkpoint repositories along the way. So once we're done with a certain
section of code, if you get lost or you're having errors, you can always reference that checkpoint repository to have it a starting point Midway through the process. We're going to be doing some debug later on using the Redux devtools extension in Chrome. So if you don't have that already, you might want to get that installed quick if you want to follow along you'll be able to see what I'm doing either way. So up to you if you want to take that extra step. I'm a big group, obviously, so I'm not going to have plans to take questions along the way but we have Jorge over here.
So if you're having any trouble along the way and you have a question, he's familiar with ngrx so he can probably help you out. So she get started with some introductions here on my name is Aspen Peyton, as I was introduced my background long-term has not been an angel or I actually worked for 19 years at IBM doing back into the element of the last several years all in Java and then I decided I was done with that and I wanted a big change. So I move less than 18 months ago to the Mayo Clinic and started learning angular there with the team that I picked up work with.
We're all kind of on the same track and I've got introduced to ngrx there. So just a certain expectations for this presentation on cuz I've been chatting with people since I've been here and there like all I'm going to go to your your presentation cuz I want to learn about you know, if ants ways to extend the pattern or to introduce to debug within my ngrx application. This is not the session for you if that's what you're looking for. This is a very basic introduction to ngrx. So if you're already familiar, The pattern and you want to go beyond that
there's an advanced course. I heard one of the other ballrooms on rxjs during this time. If you are looking for an entry-level understanding of ngrx and you want to take a step back look at the overall pattern and how to implement it in an application. This is where you want to be. I also note that just listening to some of the pictures yesterday has taught me that I'm nowhere near the expert on TRX and I've have some takeaways that I'm going to be looking into when I leave here just to advance my own knowledge of the pattern. There's just a lot
of new functionality to incorporate in this whole Community move so quickly. So I'm going to talk a little bit about my my journey and how I ended up here. I mentioned that I'm at Mayo and while I was there and starting to learn angel or I had a co-worker tell me. Hey, you should really be using ngrx. It's a cool way to manager State and I thought I don't really know why I need that. I kind of had a missed understanding that maybe it was related to routing in my application. It was totally aware. I had I wasn't I wasn't getting it all and this was
in February of last year. So the aha moment that I had was when I was working on a Sandbox application and we were just you know, kind of trying to get a starter project going and we had a couple of sources of input we had we could be pulling patient data from the Enterprise level or we can pull patient data from our registry store. It was just a local server that we had set up with our team. And so I had to set up and you could choose which source of data you wanted and whatever Source you picked we would draw in a list of patients and populated on
the screen and then you could click on a patient and we bring up all the details of that patient. So you could enrich some data related to that. But as soon as you click on a patient in the list and it went and loaded a new page with details for that patient, I lost the knowledge of what my data source was because I know it was in the last page and so then I start thinking oh my gosh, I'm going to have to like start passing data between my pages. And that's when I had this all high moment. That's why I wanted ngrx because if I could just order that knowledge of what my data source was in
my state then any component in my application would have access to that knowledge and then I wouldn't deal with having to pass today at all over my application. So if I had that moment of realization that I wanted to learn ngrx, I embarked on a mission to find education about it and it was really easy to find education sessions that just talked about the general pattern and the high-level concept of indirect, but I really struggled to find a basic application that would help me understand how to take that pattern and translate it into cuz I found myself just taking
other people's code and trying to pick it apart and understand the process and it was not an easy. It was not an easy task and a lot of the Examples that were out. There were very Taylor to a specific industry. I might have been Financial really did or manufacturing or something like that. So it's having a hard time getting wrapping my brain around the whole thing. So initially my when I cover workers stumbled upon an article that used an analogy that related that injects pattern to an apple and it said here's some actions you can do with your Apple. You can wash your Apple
and take it by the drop on I thought I love that analogy. I mean anybody can relate to analogy of an apple. It's not industry-specific. So I said I'm going to write that program. I'm going to write a program about fruit and then I'm going to teach the rest of my team. How ngrx Works based on fruit. And from that it kind of that I went to a local conference and just talked about the work that we were doing it mail. It was not this workshop at the time, but they told me about this conference and I thought hey if my team learned about engerix from fruit, maybe other people might want to learn
about in Jackson fruit. So I threw it out there and here I am. So why do you want to learn ngrx? In our case, we in our the V1 version of application. It was written before I even came into Mayo we were passing data up and down two different layers of controllers and it was very difficult to track who was changing information is hard to debug and one of my co-workers just called it spaghetti code. So one of the reasons we were trying to implement in generex and our newer version this to avoid the spaghetti code because your ex
gives you a single source of Truth for your entire application anything that you want to communicate between your components, you can put it in the store. And then if that store gets updated all their components or subscribe to that have immediate feedback that that information has changed. Using the pattern also gives you consistent Behavior through application because any component that is updating your state is following the same rules for making those updates. So it's very easy to track changes that happen within your code. There's also some great parks for testing and I mentioned the
Redux devtools at front and will it look into that a little bit more later on in the session and another useful thing about it is that it's basically the Redux pattern the pattern that in Jared's Implement is called Redux and it's applicable across Frameworks. So the Redux pattern is also implemented in react it's implemented in view. It's implemented an ember. So once you understand the fundamentals of that pattern, you can take that knowledge across platforms. However, it might not be for everyone. If you have a very simple application a single page application and you have
no need to pass a data around and have the single source of Truth between your components. Then you might not need the overhead because it does add a layer of complexity. Your application to implement this framework. So we're going to start with the very most basic pattern you can get in ngrx. I'm I already told you that we're going to have a single source of Truth for application and that's going to be already at a store. That's where anything that we want to communicate between or components will be located. And then we're going to define a set of
actions that will be the things that we can do with our state the ways that we might want to change it. However, actions are not actually going to update the state or change it that is going to be done through producers producers of the only entities within this function that will update your state and reduces are pure functions. So given the same set of input values. They'll always have the same set of output values. There's not going to be any additional logic with any of reducers. If you need some more complexity, we'll get to that in like the third pass through this pattern a little
later on one other thing. You should know if it says state in this pattern is immutable, so you're not going to just updated and place the reducer will always create a new copy of the state make any changes that are necessary and overwrite the state within your datastore and having this immutable State and having this history of changes to that state and gives you some benefits when it comes to debug because you have that history of changes and very clear and concise way so that all again come up later. In this talk, so I gave you upfront these lengths.
These are the same ones you had. I just want to reiterate for people that might have come in late or not gotten to them quickly enough. The first link is the slides if you haven't gotten to them already. The second week is our started application. So everybody should go to this link and Fork the repository if you're planning to code along here. We are going to have in this stuff looks repository of the skeleton code structure. The HTML is already written and we're not doing anything with h came out here. This is not the point of our conversation today. We're focusing solely on the Redux
code implementation. And then again the redacted of tools extension to your prom if you don't have it already and you want to get it going at the pretty quick install. So do you guys have yeah, absolutely. Let me get back for you. I'll give you a second to get here tour starting point. If the stack what's URL is too long. It's also embedded in the short slide URL. Okay, are we generally okay all caught up. So I'm going to be flipping back and forth the screen up here between my slides
and stack was so I can code along with you guys, but my general format is we're going to look at the slide and talk about what we're going to do with Overstock with and coat it and then we'll come back and just check point where we're at before we move on. I ran into some issues when I was doing this trial runs where I would flip over stuff with him who's my mouth and I had to kind of jump out of slideshow mode. So hopefully it's not going to happen, but I might have to jump through hoops along the way I said if that's the case, but we'll get there in the end. Okay. So starting
out our first step here is going to be to define the state of our banana has worked in an application. Not the Apple app that I know Sally Saw but I just like the actions you can do with a banana better than an Apple. So that's where I went with us. I'm you'll see throughout the the pattern here. I've kept the simple pattern that we just talked about and the upper right corner of the screen and where height the little yellow highlighting is going to show you where we're at in the pattern for any piece of code that were implementing. So we're starting out on the store because we're going
to define the state of our banana and the things we want to know about our banana are is appealed. How many bytes are leftover? Banana? And what color is it? Because the color is going to tell us if it's a fresh banana or banana. And then also we need to find us a general initial state of our banana here. We're just going to leave an empty State because we're going to Define that in the Shoal date of a fresh banana or self. I'm going to flip over while I'm going to try to flip over to stock list. And we'll get started. So the first thing we need to do.
In our banana directory this already exist is we're going to create a new folder called State because that's where we're going to store all the information about the state of our banana. And within that folder we want to create a file. and we're going to call Banana. State. T f When we get to the code inspections here and there was actually code being written. I'm going to try to not talk while I'm coding because I'm going to assume that your coating too and you're not going to hear what I'm saying while we're all Cody. I tend to talk to myself though. So I'm going to I'm
going to make an effort. So we're get going here on our first piece of code. Except that I'm not typing. We change the size of the font on here. So hopefully it's big enough for you guys to see. That's why I've got my initial State typed out here. So I'm going to flip back while the rest of your finishing up and just reiterate we've defined the state file. It contains the things that we want to know about our banana things that we want to track within our application.
flip to slides The next thing we need to know is what are the things we can do with our banana and we're not going to do all of our actions upfront. We're going to follow this pattern through in a few iterations. So you guys can get a consistent feel it seems like in the last yesterday when I was sitting through these 20 and 5 minute sessions. It was like a lot of information coming at me all at once and had to just take some notes for things. I wanted to follow up on and I'm trying to do the opposite of that today. We're going to take the flow and reinforce the
ideas so that they'll make sense and you'll be able to take away this knowledge of how to implement this pattern. So the first thing that work with the first action we're going to Define about a banana is how to get a new one actions within the Redux pattern. I'll follow the same pattern and they're very slim pieces. They're all going to have a type that says what type of action you're going to take and they all have a payload. And come into the first one. We're not going to worry about that payload. We're just going to pass nothing interaction. So we're just going to Define that
payload with interaction isn't any stop looking back over to our stackblitz. And my command-tab does not like to work well on this computer. So we're going to create a new file again within our state directory because this is part of how we're tracking the state of our banana. And this one were going to call Banana. Actions. TS. So all you guys are wrapping up just to reiterate we've created an action here to get a new banana. We Define the type as getting a banana and are
Constructor simply has a console message in it. So we can pop up the console in our browser just to kind of see what's going on. It's an easy way to see what what are Is he doing as we progress? I'm just kind of listening for typing to see how many people are done. So we talked early on about the fact that our action is not going to actually update our state our action tells us what we're going to do what kind of actually want to take to affect our state but
the only entity within the pattern that's actually going to make a change to our store is the reducer. So the next thing we need to do is create our reduce her file and is going to handle or action that we just played it up. So the essential structure of a reducer is that it's going to be a switch statement and it's going to switch on the action that it's listening for. So for the first action, we want to have a case statement within our switch to handle the get new banana action and we're also at the bottom here going to create the default which will just return the current state so far are
banana case. We don't have a banana to find yet. So all we're going to do is set all of the properties of our banana to what we want our new banana to be In the default case here. You can see we're using the spread operator and we're just saying get a copy of whatever current state was passed in and return the same thing back and we'll use that spread operator to create new copies of our state in future actions that we would then one of moderate change a little bit. Hilltop over and get going on a reducer. This file is going to be banana. Reducer.
T s and it's also going to be created in that same state directory that we just created. Thank you. So it's telling me her that it doesn't. Like my banana actions file, but I've seen a few cases in stock. What's where it says? It doesn't like my file, but my file is there and It'll recognize it. So we're just going to move past this and hopefully it all resolved and will the deal with that when we come to it. It's still a problem. So we're going to flip back over to our slides here quick and just recap one more time Laura
be finishing up. So we've created a reducer file. We're switching on that type of action the one action that we have at this point of getting a new banana. So we have a case statement in place to handle getting a new banana. We said all the properties of are banana with in that case statement. And then we also added a default case that will just return whatever the current state is. So before we move on to the next chunk of code, I'm going to divert for just a moment. So in this world were created in the app, we're only talking
about bananas, but in a real application, you're probably going to have more components than just one about bananas. So if we were reading this in a larger world of fruit, we might have a banana component and an Apple component in a watermelon component and those components might also have slightly different. Properties to find within their state. So we need to bring all of that knowledge up to the app level of our application so that all of our components can have access to it. And then we are components are going to access that information from the app level is through selectors. So
in this example, if we had a banana and apple and watermelon, and we brought them all together into our application Level State and then we would create selectors that would allow our components to access those separate slices of State. Then anytime exchanged every component that subscribe to it will know about that change so are banana component might only care about the banana slices State and our Apple component might only care about her apple slice of state, but we might have a fruit salad component and that component wants to know about all the slices of State. So you're going to see
when we get a little further how we get access to those slices of state and we're only going to deal with bananas in this case, but I wanted to take a step back and explain how most of multiple components with an application might want to have access to particular pieces of data so that they can all be updated whenever a change occurs. So without knowledge that we need to bring the information about our banana State up to application Level. That's what we're going to do. Next. We're going to wire this infrastructure that we just built into the application. So the first thing we need to do
is export this information using an index file from our banana State folder. It will flip back over. To our staff was and we're going to create within our state directory a new index. T s folder. From what you were going to deal with these exports? Supplements index file we're going to export the knowledge of our producer the knowledge about our actions and their knowledge about our initial banana State and the overall State all those properties that we defined within our banana. So the next step of wiring this all in
is that we need to pray the actual app level state. So we're going to create a file called App. State. Yes, and we're going to bring in that information about the banana that defines our banana slices stays so you can see here. We have an app level state to find have an app level initial state to find them. We have a plevel list of producers. So if we were to create a banana component within this world, we would also bring an Arbonne an information here. So are banana slice of state would come into the App State object. We have that initial Apple State Route into the initial stayed
at the top level and we have the app level reducer also brought in here. So a flip over and this file is going to be created at the actual in the app directory. And stock quote so you want to find the app folder here and we're going to create this fold file right here. So we just went through this process of trying to bring our banana slices stayed up to the app level. We brought in the information about our banana state or national state and our producer in this line at the very omigosh. My coat is cut off. Sorry about that. Here we go. Ok.
Now you can say the line at the bottom. That is our selector. And the selector is the thing that are components can access to say I want to know what's going on with banana slices today. That's how we're going to return all of the properties of our banana to our component. There's one more step of wiring that we have to take care of and this is to get some additional information into our app module. We need to bring in a few modules from the libraries and we need to add a couple of lines to R & G module import list.
So whenever you see this kind of white dashed line, I'm just trying to indicate that these two chunks of code are not consecutive within the application or within the part. We're working on some when we go into that module just file the top part is going to go up with her Imports stuff. And then the bottom section is going to go into your engine module Imports list. switching to our app module We got our initial Imports up at the top here and then like I mentioned we're going to jump down into RNG module Imports list for the bottom section.
So couple of these lines that were referencing here the ones I have called out on that reference the store does tools module. We are working those in here just because it's easier to do it while we're updating the app module benefit of that is actually with the Redux disposable. Talk to you later. So we'll revisit those two lines a little bit later when we start talking about debug. So now we brought the knowledge. Of the state of our banana up to the APA level and we've done all of this wiring that we need to add. So now we can actually go to our component and
try to exploit all this infrastructure that we just spent time adding. So we're going to go into a banana component, which is already existing in your skeleton project. And we're going to add some imports that we need to get access to this information. We're going to create a banana dollar sign. Which is representative that it's an observable and when we flip back over to staff, what's I'm going to pop into the HTML for just a minute so you can see where we try that in. We're not doing any changes with HTML, but it helps to know how this variable within our component is tied and Sage came
out that we're going to see when we get all of this wired up. So are constructed within are a component just needs to bring in the store and then with an RNG and yet we're going to request a new banana and that new banana function within here is just going to dispatch the action. We prayed it to get a new banana and then the energy on adults also going to set up that link between our banana observable and the selector that we created to get our banana slice of state from our store.
so switching tour bananakin Play Store just going to add the code as a needed within those functions. So what you got your Imports at the top we're going to go down right above our Constructor to create this banana observable variable. Then we're going to define the values that are coming into work instructor. additional functionality We're just addressing the joys of Life coating up here. So give me a second. Thank you. I swear yesterday. I went through and I actually literally copied and pasted all of my coat out of my slides into my app and it worked
fine. So this is this has been quite an adventure. So I'm still getting an error here. I'm going to dispatch the action and it made magically this work because sometimes these errors and stuff looks just resolved. So for one second, let's take a step outside and look at this HTML. Like I mentioned we were going to upfront this line right here is the magic that is bluing are banana observable that we created using the a stink pipe to our store. So back in the banana component. We're saying we're accessing the selector. I'm
resigning it to our banana observe. Also that anytime we update the state. This line will be executed and then are HTML will have knowledge of that new banana. So the next thing we need to do is actually dispatcher action. And once we dispatch the action if all of these dependencies resolved, it'll automatically update and are HTML on the right here. And it's not working. here points to your actions coupons Yeah, I need to go back here. Can you one second? After action got it.
The Returned Maybe Yeah, we're still not there still something going on here that we're not calling or reducer. Yes. Yeah, that's what I had initially here was just from State you're saying like this. But not that yeah. which is what I had and then I had an error and then it be okay. So I'm exposing myself as not a complete expert in this stuff, but it's part of our process. And one of the takeaways I want to give to you. All is that if you find a useful methodology of communicating stuff, obviously, I'm not doing the best
drop at that right now. But if you find a good example in a way to communicate the stuff to people just put it out there because you don't always have to be the prime no xbow or the primary expert on a topic to provide value to the community. So I feel a painful process. We finally have a new banana here and you can see down at the bottom just some text visualization of what our state looks like. So our initial state was that are bananas not fields we have is appealed his balls and our bikes remaining is nine and our color of are
bananas yellow because we have a fresh banana right now. Made it back to where I need to be in my own slides here. So I'm going to flip back to my slides. So we're at a checkpoint finally and if you got his lost if I did during that you can always refer to this track what repository and it should get you to a working version of the place that we're at right now. So what we did through this whole process was we created the definition of our banana within our store. We defined our
first action, which was to get a new banana. And then we created a reducer that has a switch statement with a case in there that will handle our get moving in action. We created at the app level. We brought all of that wiring up and we played against electric called get my banana so that are component could access it. And then we finally dispatched that action was in our component to get our initial State updated and because we had that banana observable connected with a stink pipe for HTML or HTML immediately had the knowledge that we had gotten a new banana. I've added
this first Lincoln here to the slides for anybody who missed it earlier comes in late. So that'll be repeated through all the checkpoints just in case someone needs it. So what you're probably thinking right now is that was really painful and we only got one action running. Do I have to do that every time I have to add an action to my application and thankfully the answer is no once you have this initial infrastructure in place. It's pretty easy to add additional actions to your application. And so we're going to try that next we're going to just add one more simple
action to our application. So the next thing that we want to do with our banana, is he lit? Don't want to see you. The first thing we need to do is go into our actions. ES file and we're going to add the peel banana action and I'm all for code reuse. So really you can just copy and paste the existing action to get a new banana and changed the name of it up a little bit and we'll be good to go. So we're going to jump back over to our stackblitz. Go back to our banana actions file. We need to create we're going to copy this first line here where we
defined our get newborn action and just tweak it for peeling a banana. Then I'm going to copy and paste the whole action that we created. And we got as well. And then finally down in the export statement. We just want to add our peel banana action to this Union. So we got it this additional action. But again our action isn't the part of our pattern here that updates our state. So we need to give our reducer knowledge about our new peel banana action. So now we're jumping into the reducer section of our pattern. We're
going to add the import to peel for peel banana action. And then we're just going to add a new case statement to that overall switch that's going to handle or peel banana action. And in this case within our return because we're not creating a banana from scratch. We're going to use that spread operator to create a new copy of our state and then we're just going to change the has peeled property on that states. So now that our producer knows how to handle the peel banana action the last thing we need to do to get this working. Is dispatch the
new action from our component. So we need to import are peeled an action within our component and then we need to dispatch it within the peel banana function and its peel banana function is already connected to our peel banana button that's in our HTML. So as soon as we dispatch this action, then we can try out our peel banana button and see if we can get our banana peel. Do not peel banana added to or Imports. And then you can scroll down and find the existing peel banana function and just add the dispatch to
it. And we're still not dealing with payloads yet. So we're just going to pass a null into our po banana function. So now within your little preview window if you put peeled banana. Well, I hope we get a peeled banana. You can see that the state has updated on the bottom to kill banana true. And if you're looking at your console because we've been adding some little console.log messages. You can see that we triggered an action to get a new banana which triggered the reducer then to get a new banana then by clicking the button. We triggered the action to Pilar banana which in turn triggered the
reducer to actually update our state. I can. So your new banana action should follow exactly the same pattern as you're getting a banana actually just want to make changes references from getting you to peel. So we're already at another checkpoint that first action took a whole lot of work because we were building in all of us infrastructure. But once we have that in place, it's really simple to create a new action. It'll take a few steps and in a few lines of code for actions file a new case statement
within our producer and we get to dispatch the action and we're off. So again, if you need to pick up at a checkpoint, I got the checkpoint. You are a list of here for stackblitz if you need to pick up that new Repository. So the next phase of its pattern would be a slightly more complex action because often you're going to need to pass some kind of information to your action in order to figure out how you want your steak a change. For example, if you are dealing with products or patients, you might have some kind of
ID that you need to pass your action in order to get your processing done. So this kind of action of the payload follows exactly the same pattern that we've done so far. We just need to pass a payload in when we dispatcher action from the component and then we need to handle that payload within the reducer. So we're going to do the same thing in one more time. But this time we're going to add a Halo to the next. And that should be just about as quick as the last phase that we went through. So our next thing that we're going to do with our banana now that we peeled it is we want to eat it. In
the payload that we're going to pass into our eat. Banana action will be the number of bytes. We want to take now. I should point out that I set my bites Romanian to my new banana to 9. And if you did not set your bite remaining to 9 your behavior might be slightly different than mine because the HTML works, but this is a workshop. So I didn't pray to to be the most robust HTML in the world. So my assumption would be that you set the First Baseline point of ice remaining in your banana to 9 and then every time we eat our banana, we're going to take three bites of it. If
you want to play around with it later on your own you are more than welcome to do. So, so we're going to jump it back to her actions filed. We're going to add a new action to eat a banana. Again, we can do a lot of cutting and pasting because our actions always follow the same format. So we need to initially at our Imports. I'm sorry our constant. We need to Define our eat banana action. Then we can copy and paste an existing action. And change the name of it.
The one thing we're going to do slightly differently on this action is for our payload. We're going to stay number instead of any because we want to make sure that when we dispatch this action, somebody's giving us a number so we know how many bytes of our banana have been eaten. And then again, you need to add it to your XSport down at the bottom. And just like with all of our other actions, we now will have knowledge of the number of bytes eaten past interaction, but our action itself isn't
what updates are state. So we need to handle this payload within our reducer. So it's going to still follow the same pattern as a reducer in the past were going to bring in that import and then we need to add a case statement within our switch. But when we update the state this time, we're going to take the fights remaining in the existing state and we're going to modify it to reduce it by the action payload that is passed in I want to resize this the little out I lost my variable on the wrong field around wine strain
So again within our reducer we're importing our new eat banana action Solera reducer to listen for it. And then in our case statement, we're going to handle that eat banana action. We're going to again use that spread operator because we need to create a new copy of our state and then we're going to update the bytes remaining with the bikes are made from the State minus the payload that was passed in on the action. So the last thing we need to do just like when we had our peel banana action, we need to dispatch this action for our component. So we're going to
import are even in action and then within the existing even at a function, we're going to dispatch the action and we're going to pass in that we are going to take three bites of our banana as the payload. And similar to our other functions are eat. Banana function is also connected or even a button in rui. And right here is where you're going to specify that number of bytes that will be passed in at the payload. So now that we have this all wired we can Pilar banana. And you can see the state update and then we can eat our banana and you can see our bikes for me
has been reduced to 6 and if we continue to eat our banana a couple of times we can reduce it all the way down to zero. And you can see if you're following along in the console while you can see all of these actions occur rain and being passed to the reducer. So we've been through this repetition a few times now, so you should have this a general idea down that we've created the store of information with the find what the state of our banana is. We've created a few actions that will make trigger changes to that state are reducer we created to listen for a
different actions and update our state accordingly based on what we've requested it to do. And again, there's a checkpoint repository available here if you need to pick it up. So the next pass that were going to do through this we're going to add some additional complexity. We're going to mix it up a little bit so far. This is a pattern with it looking at but I've added a question in here and that is do we need to handle an effect when we dispatch the action from our component and effect is if we need something additional done other than just passing the actions to reduce her and
having update. This would be in cases where you need to make an HTTP call to bring in some additional data ensure application, which is very common. There's not many chances. Honestly where you're going to have an action that doesn't need some side effects going on. So this is what the more extended pattern will look like if you need to do something like me and hdcp call then you need to add an effect into the pattern. You have an effect into the pattern you need to have two actions involve. The first action is
Can you hear me that was where it just looked out for me the second I was saying when you introduced. Hello, just when I get going it cuts out on. You need two actions to handle this affect you need the initial action, which is going to initiate the process. It will call into the effect. The effect will do whatever magic you want call off to whatever Services you want to involve and then when the effect it's done, it's going to map to the completion action. The completion action will take any necessary information that was gathered from the
service and pass it into the reducer to that update the state. So for this next pass through I'm going to keep having that little mini diagram up in the upper right corner. So you guys kind of know where we're at in the process, but it's going to look like this for now and we're taking out the way where it's an action. That doesn't even affect her only going to look at the action that doesn't even affect. So the thing that we're going to add in our banana world is a service that's going to jump forward in time and cause Arbonne anthrop.
So we're going to do is create a couple of new actions. The first one is going to initiate the Timehop. And a second action will be to complete the Timehop. We're going to initially create these two actions. Then we're going to create the effect that's kind of the middle of that sandwich between them that affect is going to call off to a very simple service that will write and all the service is going to do is wait for few seconds and then return the color of our rotten banana, which will be Brown. So we're supposed to get first get started on these actions and his actions are no
different than the actions. We've created so far. So really you can just copy and paste again and we're going to update them a little bit to be our initiative. Initiate Timehop action and our Timehop complete action. So again, this will be back in a banana actions file. So are you guys are finishing up will just jump back to the pattern here. Again. Our focus is on these initiation and completion actions within the pattern. And we've added to our code the constants that Define our new actions.
The code that is going to Define what we need to do the type and payload of our actions and then we added them to our Union statement down at the bottom. So before we actually get to our effect, we're going to create this little service that's going to do our time out and then return the new color are banana. So we're going to call this service or rot service. And will jump over to stack let's and we're going to Define this service at the app level of our structure. So up at your app folder to create a new file.
And when I call it Rock. Service. Yes. Maybe some fresh batteries will keep me from flipping out on you guys. So I got my service created. I'll give you guys just a minute to catch up. If you need a little more time. I'm going to flip back over my slide and just talk a little bit about what we're doing here. So important just a couple of modules that we needed for injectable and observables. I have Anna ductable decorator on here simply because it saves us
the time of having to Define this provider at are at module level this Little Rock. Banana service. All it's doing is creating an observable and setting a timer and when are 10 seconds is up. It's going to stick with the word Brown and turn observable and send it back and that's all we needed to do. So then we'll complete our observable at that time. So now that we have our service created we're going to jump in and create a new effects file and that's going to be the thing that listens for the initiate Timehop function calls after the service. It'll wait a
few seconds for the service to complete and return the new color of our banana and then it's going to take that new color the color brown and it's going to pass it into our Timehop complete action and dispatch that and then I reduce her will be listening for the time pop complete action and it will update our store with our new state. So jumping into effect. Looks like we can see everything here. So it's got several Imports that we're going to need to deal with but the overall number of lines in our effect
is going to be pretty small. Like I said, we're going to the other type line right here. If I get my mouse to show up is the line that's going to say we're listening for initiate Timehop action when we catch it. We're going to call our Rock banana service here and we're going to be switching our initiate Timehop action to a Timehop complete action passing in this color as our payload Flip Flip over and get this coded up in our project. We are going to need a new file for this one. So within our state directory, we're going to create a new file for our banana sex.
We'll just call it. Banana. Effects. He is You can see my effects is complaining a little bit about a couple of my imports, but we're going to cross our fingers and hope it's the same as the other followers complain about my importance. Summer flip back to the same code in my slides for just a second. So to recap our effective listening for our initiation action, it's going to call off door service. The service is going to wait a few seconds and pass a value back toward effect. And then our effect is taking that value sent back from the service and it's going to send it into our completion
action. Find Outside service or component is the part that needs to trigger to dispatcher initiate action, but are reduced her in this case is going to be listing mean for our completion action. So now that we have both of our actions are service and our affect all ready to go. We need to go into a reducer and add a new case statement to handle. Sorry. I was ahead on my on one laptop. Not the other one. So we need to go into a reducer and add a new case statement that's going to listen for that time hot complete action. So it's the
same pattern as we saw with our eat banana because we're going to deal with a payload that we're going to assign to our color property within our banana state. And then we need to import our Timehop complete action oven or Imports. So hopping over we're just going to go into a reducer file. Get that completion action imported. And then we'll add the new case statement. And we're going to keep our spread operator here that's grabbing our copy of our current state and then we're updating the color property in this case
to be the payload the past interaction. So now that our reducer is listening for that completion action out. Let me flip back over to my sleds. Now we've got to reduce her listening for that completion action. So the next thing we need to do. Is actually not jumped or component quite yet because we are now bringing in an effect into the picture which means we got a little bit more wiring that we need to add at the app level so that our app to knows about our effects. So there's
three different files were going to change her first. We're going to go into that index. ES file that's dealing with all of our exports related to our banana State and we're going to explore new effect at that level. Then we're going to go into our application Level State and bring in that effects related to a banana slices State and then we need to go into our app module and pull in a few more Imports and modules that level on this last line here is not an import. It's actually going to go with an RNG module into the art import section. So we'll get we'll tackle these one
at a time. So first things first, we're going to go to index. ES file. and deal with us new export and you can see I am getting a request to install a new package over here. For some reason. It doesn't seem to know a package at 1 so maybe if I finish the flying at will Or maybe I just took a knee that importing more. I've gotten that import request a few times. So if you're getting in your little preview window or pressed to install a new dependency just go ahead and resolve that dependency. If you click on it, it should install it for you. If not, you're good
to go. So we're exporting this are banana effects from our index file. Next. We need to jump into our app. State. ES file. Remember this is where we're collecting all of information about our banana slice of state and now we've added effects to are bananas. So we need to have that knowledge here as well. weather in a spell equals After here, thank you. Love a helpful audience. Okay, so we've got our export up at the app level now that's bringing an Arbonne an effect knowledge for Apple state
so next we're going to jump over tour app. Module. T s and deal with these additional Imports that we need to pull in on the first one on my line 8 we've already got an import statement bringing in our initial State and our reducers, so we just need to add an effect to that line And then we've got a few completely new Imports to add. And then once you have those Imports resolve, we want to jump down into our module Imports list. And we're just going to add a line
for effect module. So again, we exported the knowledge of a banana affect former index. We pulled that knowledge into our app level State and then we did a little bit of wiring within our app module. She got the knowledge of this new functionality. So we already went through the pattern and created our actions we Creator affect we created our service but the producer was only listening for the completion action. And I mentioned that are component in order to trigger this whole process needs to dispatch the initiation action. So we're going
to bring in our initiate Timehop action into a component the important and then there's an existing Timehop function within Your component and we're going to dispatch our time pop action. So let's jump back over to our banana components and get this wired up. So are Timehop function here is obviously connected to our time pop button. So let's try to go through our whole pattern here will Pilar banana? We can see that our state updated to indicate is peeled is true. And then we can eat our banana a few times until we don't have any bites left. And
now we're going to try try going this time hot function. And remember it's going to wait a few seconds and then it should update our state with the color brown. So I can sit down in my console that my rock banana service was triggered. and Wallah, we can stay there about service completed and now the color are bananas been updated to Brown and the magic of having our banana observable within our component tied directly to our HTML automatically will update that state of our banana as soon as the service has returned and
our reducer went through enough and updated that color within our skip So we finished our basic pattern at this point. We created a few actions on our last pass through we created an effect with a couple of actions to handle both initiation and the completion and we created a service provider banana. We went into a reducer and added to a switch statement the case to handle our completion action, and then we went into a component and triggered that initiation to start the whole cycle rolling. So, this is our final
checkpoint for codeine with in this Workshop. We're going to take a step aside now and talk a little bit about the d d bug who holds the deed of tools that we can use to debug your application. So we're going to switch back to stack with and look at these two little bit more closely. But in my opinion this was one of the biggest advantages I saw of NPR up because having this pattern of always updating with a new copy of your state gives you this history so you can go into the dev tools and see exactly what has happened over time with a nurse said it's really easy to set up
and use if you've already installed in your browser, you can see how he see the setup was and also aside from just the debug tools from a unit test perspective. You know what your state looks like. It's really just an object and so you can feed pretty much anything into your state from a test perspective to try to trigger certain circumstances within your application. Mixpre really robust test framework, so I mentioned up front the Redux devtools plugin for Chrome, and if you missed it up front, you can always pop out and install it quick now.
And the other piece you need to enable us functionality is something we code it up pretty early in the workshop. It's these two lines here that bring in the depth with functionality and in the bottom section here, you'll see we have a max age configured of 25 and that's telling us that we want to maintain a history of 25 actions within our history. So if I don't need to know that much I could say I only want to keep track the last five actions if I want a whole bunch of History because I'm having a problem. Maybe I want to keep track of 100 actions. That's where you would update the
size of your history here. So I'm going to flip over back to my stackable it's quick. And if you can see this a little tiny icon appears, it's kind of teal-colored. If I was on a web page where Redux was not enabled this would be great out but because I have read text enabled you can see that it's colored at this time. And so I can click on it. And it is not showing me the right thing right now. Let me get back out of here for a second and refresh. We're going to refresh this and then kind of flipped through our actions really
quick. So we have a fresh history. Out and you know what? I know what the problem is. So there's a little button up shirt that says open a new window. We're going to just take our application and open in a separate window within the stack with the world. It kind of confused about whether it's tracking the history within stocktwits versus the history within the app for trying to test so I can open this in a new window jump through our actions again quickly. I'm going to skip the Timehop so we don't have to wait 10
seconds. And then open our deductibles so you can see right here. We have a list of actions. I would make this bigger for you if I could but it's if I disconnect it from its current location it slips back to stack with tracking. So I'm kind of hamstrung in this regard. So hopefully can see this okay, or you can look at it on your look laptop. So there's a nice little filtering function up here at the top. So if I afford Emily wanted to see my eat actions, I can just type that word in there and it'll filter my list down. If you're working in a much larger application. You might have a whole
bunch of actions going on. So. Soul Train capability can be really helpful. I can also because I see the history here. I could go back to this get new banana action. I could say I want to jump to that point you can see it update and then I can hit play here and it will start to flip through everything that's happened since that point within my application. Also off to the world right attention to that Far Side here. I'll just click PMI banana. You can see up in the corner here. I have the disk selected. So when I select an action within my West it's going to show me what
changed when that action occurred. So we're saying because I peeled my banana at that time that actually occurred we changed the is Pele property from false to true and similarly if I click eat banana, you can see we change the bites remaining property at that time from 9 to 6. There's a few different ways. You can look at your state within the debug schools here. I can just flip to my state button and instead of showing me the differences when a particular action required. It'll show me the entire contents of my state at the time that action occurred. I can look at it and it preview I
can flip the chart and look at it in a chart view not super helpful when you're dealing with the super simple state, but in a much bigger State this chart view can be helpful and I can also look at the store raw. Json style structure. So you can see how having that ability within a larger framework when you have multiple multiple components that could be dispatching actions and multiple components listening for things. It can be hard to know upfront which component is responsible for a change in your state. So having this history available within your debug tools can
be a really powerful way to debug your application and figure out exactly where your banana turn purple instead of brown. So that's basically what the main content I wanted to cover with you guys today and hopefully you found it helpful. I think there's a lot of confusion about the pattern in general. So sometimes soon as it gets thrown into the deep end and we're just trying to figure out and it can take if we take a step back. I can kind of help us understand the pattern and a little more depth. I have extended this pattern in my own work a little bit further than
we covered today. I'm for example involves a little bit more layer of complexity. If you're working with modules, you have to Define air selector slightly differently, but there's a number of demos out there that can give you some guidance in that area. We found it helpful to also put a hook into our code that gets called it app initialization so that we can retrieve a configuration file that we need to know. I like our user information who's using our UI. And if we put that hook in an app initialization, we can grab that config file and have it automatically load it into our store up
front. So we have it available from the moment an app is loaded. I'm I also was able to integrate it a little bit with Dynamic components. So we had a scenario where based on the field that a user clicked on on the left side of the screen. We wanted to update a different are loaded different component on the right side of the screen. So we might have had to visualize data from a document Source or laboratory results and some different components that we would need to load based on what kind of data the user wanted to look at. So by tying this into ngrx, we could take the knowledge
of what the user clicked on on one side of screen load it into the store and then automatically Titan to that store the knowledge of what kind of component we needed to load based on that and if this is something that now you've understood the pattern that you would find useful to have examples of my Twitter handle The last page that we'll get to in a second. If you tweet me I would be happy to go out and create additional GitHub repositories that shows some examples in code that would extend the banana app to these additional use cases if necessary. It was just beyond the scope of this
Workshop, so I didn't have time to get to it before hand. Again, I'm reiterating the presentation slides are available. If you need to access them later, I have a link in here to an article called explain read acts like I'm five because this is where the the Apple analogy came from that started me down this path of creating the banana app. The third lie here is a narwhal blog post that somebody directed me to early on that has some visualization of more advanced patterns, you can use with ngrx that I found really helpful and I haven't had a need to
implement them yet, but it goes through possibilities like you might have an action dispatch that you need to split into multiple actions to deal with asynchronous operations. And so it was a really solid way to get a visualization and flow charts of how you might want to tackle those things within Redux. And then finally, I have a link to general information about my employer. So here's my contact information. Feel free to reach out to me anytime. I'm going to be in the speaker panel this afternoon in about a half hour. You could catch me there or if you just see me around and you want
to chat. I'm always up to talk to people and I'm here by myself. So I have nothing better to do than talk to stranger. So thank you very much for your time. I hope that you all found this useful and I would like to reiterate that you don't always have to be the expert to provide value to the community. So I strongly encourage everybody to participate in the community overall. Everybody has been so welcoming and I think everybody appreciates when we can share experiences that might benefit each other. Thank you.
Buy this talk
Access to all the recordings of the event
Buy this video
With ConferenceCast.tv, you get access to our library of the world's best conference talks.