 Hey, buddy, what's up? It's Rob Dodson. Welcome back to The Polycast Show. So today, as part of popular demand, I'm going to be covering the topic of using Redux with Polymer. So a lot of people have asked for this, how do you manage state in a big Polymer app? How do you share state between all of your components? So I thought it'd be cool to try and tackle this subject. Now, Redux itself is a very big topic. So I'm not going to be able to cover every single facet of it today in the show, but I will link to some content down in the show notes, some educational materials. You can learn more about Redux on your own time. But I'm going to try and give a short synopsis of how Redux works, and then we'll look at how we can build a very, very simple Polymer app using the Polymer Redux behaviors. So follow me over here to my laptop. I've got a little presentation that I've put together for you to try and explain conceptually what Redux is and how it works. So when you're building a Redux app, your app is going to be composed of views. If we're using Polymer, you can think of these as your Polymer components, OK? Now, a view in Redux land, it's typically going to be the kind of component that maybe has a few components aggregated inside of it. So every button and dropdown and things like that, those might not all be hooked up to Redux. But maybe the component that holds all of those children together, sometimes in Polymer, we refer to these as mediator components. If you use React before, they're often referred to as container components. So these sort of components that aggregate a few very simple children will be connected up to our Redux system. So we've got our view, and what happens inside of the view is it's going to listen for changes. So today on the show, we'll be building a little friendless thing. So someone can add a friend and hit a button, and it'll save it to a list. So the change there would be the user clicking on that button and adding a friend. So what happens is our view is going to, when it hears that user action, when it hears somebody clicked on that button, it's going to dispatch what in Redux LAN is referred to as an action. And an action is quite simply just a little object that has a type, so some sort of string constant, in this case, add friend, and then usually a payload value of some kind. So in this case, our friend that we're going to add will be named Eric. So we dispatch that action in response to the user clicking a button or something like that. That action then gets handed off to this thing called a dispatcher. Dispatcher is actually what takes that action object, and it hands it to what are called reducers. Or in this case, we're just going to build one big reducer. A reducer is a function that looks at the current action that's coming in, and then based on that action type, and based on the payload in that action, it generates some new state for application. Now, the interesting thing about Redux is that it takes all the state for your app, and it keeps it in one big top level object. So any change in any action dispatched by any component is going to update that one big state object. So inside of our reducer, what we're going to do is we're going to look at the incoming action. So in this case, the action type is add friend. We might run some code. We might push something into an array or something like that as part of our state. And then finally, we'll return that state to the outside world. Now, both the dispatcher and the reducer live inside of a structure called the store. And normally, when you're building a Redux app, you'll have these components that subscribe to updates from the store. Using the Polymer Redux library that we're going to be working with today, that whole subscription flow is actually just going to be automated for us. But basically what happens is the reducer says, hey, I've got some new state based on the action that just happened. And then the store says, cool, I've got that new state. I will now hand it off to all the views that are listening to me. Now, the cool thing about this is we don't have to limit this to just one view. Because we have this one big store, we can have multiple views listening to that same store. So component over here can do some updating. It can change something and dispatch an action. And then these other components around it can also get that new state. So that way, we don't have components that are trying to talk to one another, which is nice. We keep them decoupled. Instead, all the state just sort of flows into them unidirectionally. So everything that we're going to do today is actually going to be one-way bindings, because we're just going to go in this sort of little loop here. All right. Now, I know that that's a lot of weird abstract theory. How about we get into our code editor, we actually start writing some code, and hopefully that will help some of this make a bit more sense. So follow me over here to Visual Studio Code. And I've got a very simple project setup. The first thing that I'm going to need to do is actually go into my terminal. I'm going to run Bower install, Save, Turner, Polymer Redux. I've actually got that already installed in my application. So let's get that step. And the next thing we're going to do is we're actually going to use NPM to install Redux itself. So do NPM install, that's just Save, Redux. And that will then pull down the Redux library to our application. Cool. So those are really the only two dependencies that we're going to work with today. And now in Visual Studio Code, we've got our Bower Components directory, and we've got our Node Modules directory with all of our dependencies set up for us. All right. So I'm going to set up a little index HTML file then. And I've already kind of stubbed this file out. This should look pretty familiar to you if you've worked with Polymer before. So the first thing that I'm doing is I'm pulling in our Web Components polyfills. And then I'm making sure that Redux is included in the page. And then I've got a couple elements that I'm going to build today. Friend counter, friend input, and friend list. I'm just including the imports here so I don't forget. And then I've got the actual elements themselves commented out down here. So as I'm implementing each one, I will comment these back in and you can see the results. So let's start by defining our Redux Store, the thing that's going to be consuming actions and generating the state for our app. Now, the way that I typically do that is I'm going to create a Redux Store HTML import. And inside of this, just like we're working with any other Polymer element, we're going to import Polymer Redux. And then we're going to create a script tag. And inside of the script tag, the first thing that we want to do is we want to generate the initial state for our application. So this is just like the user hits the page for the first time. What does the app look like? So I'll define a const. And I will say initial state equals an object. And this is a really simple app. So we're going to say the only state that we initially have is this empty friends array. Next, I'm going to define our reducer. So I'll say that my reducer is going to be a function that takes state and action. And then typically, what you see with reducers is they go through and they usually make a switch statement. And so they sort of do a switch case based on the action that is coming in at the current moment. So we're going to say, all right, so based on the action that's coming in, what kind of state do we want to return? Let's see. So if there's maybe no initial state or anything like that, let's actually go ahead and return our initial state. So if no state was passed in, we'll return the initial state. Then we can switch on the actual action that was passed in. So we'll switch for action.type. And in the app that we're going to build today, we're only going to have one action type. It's going to be add friend. So we'll say, all right, cool. So if action type is add friend, now we want to do something to modify our initial states. We're going to take our initial state and we're going to sort of move it to the next phase. We're going to add whatever friend was just passed in. Now in Redux, what is often done is you often make sure to sort of copy your state. So rather than mutating the one big global state object, you try and make it immutable. So you actually copy it. And in that copying phase, you might insert whatever changes you have. So every time you're modifying the state, you're creating a new copy of the state and you're adding whatever changes you want to do. So we're going to say friends equals state.friends.slice0. So we're making a copy of the current friends array. And then we're going to say friends.push. And in this case, we're going to be pushing in the new friend name from our action. So we'll say action.friend. So we're pushing that into our friends array. So that would be, we'd just be pushing in a name like Steve or Eric or Monica or whatever. And then the last thing we're going to do is we're going to return the new state object. Now, the pattern that I've often seen done in Redux goes a little something like this. You do an object assign, you take an empty object, you take the current state. So we're taking the current state, we're copying it into a brand new object. And then we take whichever little mutation that we're doing based on our action. So that'll be the last thing that we copy in there. So we'll say the last thing we want to copy in is this new friends array that we've created. This is a pretty straightforward, simple reducer. It only has one action that it supports, but we could add multiple actions to this. We could add, you know, remove friend. We could sort friends. The cool thing about this is it kind of just like scales infinitely, which is really nice. Now the next thing we want to do, now that we have our initial state and our reducer, is we want to create a store and we want to create a behavior that we can hand off to all of our Polymer elements. So we'll say our store is going to be equal to redux.createStore and pass it our reducer. And then we're going to say redux behavior equals PolymerRedux and we'll pass it our store. So if I haven't made any typos, I believe this should create a behavior for us based on that store that we generated and now we can mix that into our different elements and they'll just get notified whenever we update our data. So let's try that out. We'll create a new element here called friendCounter and the first thing I want to do in this element is I want to make sure that I'm pulling in Polymer. So I'll pull in Polymer and I want to make sure that I pull in that redux store that we created. So we'll import our redux store and now we're ready to start stamping out this new element. So we'll call our element friendCounter and the only thing we're going to do with this element is we're just going to display the current count of friends that the user has. So basically just taking the count from that friends array from our store. We want to make sure that we mix in our redux behavior. So we'll say behaviors, redux behavior, like so. Okay, and then the only property that we're going to have or we'll have two properties actually. So we'll have one, which will be a property for our friends that gets passed in. So there's gonna be friends, this is an array and the one piece of unique syntax that the redux behavior is going to give us is this thing called state path. And we're gonna set that equal to friends. So what state path is doing is it's saying, okay, what is the path? How do I link this property up to the one sub property in that big global state object? So for instance, because we have that big state object and friends is just an array right off the root of that object, our path is just friends. But it could be nested, you could do something like if you were looking for user.address, you could do something like that, that right here, right? So you can kind of work down sub properties if you need to to link up the property in this element to your big state object. But in this case, because friends is right on the root of our state object, we can just say our state path is right there. Okay, so that is going to connect our element to the friends array. Now the next thing I wanna do is I'm gonna compute a property based on the total number of friends that we have. So I'll make another property called friend count. So this is gonna be a number. And this will actually be computed and we'll give it a computing function called compute friend count friends like that. And compute friend count function takes that friends array and it's just gonna return friends.length. Pretty simple. So now in our template, we're going to just say we'll have an h3 in here and we'll say you have friend count like so, okay? So let's go back to our index file. Friend counter is already ready to go. So we'll uncomment it in the body. Go back to the Google Chrome's refresh the page. You can see right here, it says you have zero friends. But we can play around with some of that initial state if we want to. We can go to the redux store and we can say, oh, okay, well, I have a friend, Monica's my friend, right? So we can change the initial state in our app and go back and verify, ah, we have one friends now. Cool, you know? So that way we know that the initial state is working and it's being piped to that element. Let us then modify that state. So let's now create a component that'll let us add some more friends to this array. And hopefully what that should do is update the count in our friends counter as well. So I'm making a new element called friend input and I'm just going to steal my imports from friend counter. So I'm going to grab a Polymer. I'll grab the redux store. Give me that over there. Boop. So friend input. Got to make sure to not forget our redux behavior. I forget this all the time. As I've been working with this thing, I've realized that's probably the main mistake I make. I forget the behavior and then I'm like, how come nothing's working? Why is this not updated? So I'm going to make sure the redux behavior is there. And this element, we're going to have basically two very simple things. We'll have an input field. So someone can type in a friend name and I'm going to give it an ID of field. There we go. And we will also have a button. Just says add friend, okay. And we'll say when someone, we give the button a handler of on tap. When someone clicks the button, we will run the add friend function. Now, the next interesting thing that the Polymer Redux library gives us is it gives us a way to sort of like, take what in Redux are called action creators and actually just sort of like make them part of our component. So we can sort of pre-define the actions that this component can spit out to the rest of the world. So we do that by adding an actions object. The same way that we add like a properties object, you can add actions object. So the actions object here, I'm going to have an action called add. And that is going to be a function. And that is going to return an object. And this function is also going to take like our new friend's name. So we're going to return an object. The type will be add friend, add friend. And the friend will be that name value that we pass in. Okay, so far so good. Now, the last thing we're going to do is we will implement this add friend function, this thing that happens when you click on the button. And what that's going to do when we implement it is it's going to basically get the value from our text field and it's going to dispatch this action right here. So let's go down here. We'll say add friend is function. First, it's going to say, all right, our field is equal to this dollar sign dot field. So we can reference it more easily, right? And we'll say if the field has value, you know, if someone just like clicks the button and there's nothing in there, we don't want to do anything, but if they've typed a name, then we're going to say this dot dispatch add, and we're going to pass in the field value, right? So that will trigger this action creator right here. It'll pass in the name and it'll dispatch this object to our reducer. So dispatch add friend with our friend's name. That'll go to our redux store, which will run the switch statement. It will say what action was it? It was add friend. And then let me find the action dot friend property and push that into the new state. So that's what we're doing there, right? So we're going to say dispatch the friend value and then we'll do just like a little bit of cleanup. So we'll also say field dot value equals null just to clear out the text field. And then we will also call field dot focus to return focus to the field after someone's clicked on the button. All right, see if this one works on the first try. So we got to go to our index page, put the friend then put back in there. All right, refresh the page. Okay, cool, I got my little input here. So my initial state says I have zero friends. I'm going to add Monica, add friend, and oh, it's totally busted. What did we forget? I forgot something. Ooh, type error. This dispatch is not a function. Let's see, friend input. All right, where'd we go wrong? Add friend function, redux behavior. We got the redux behavior. All right, it's in here somewhere. Hold on, folks. We're going to fix this. Ah, wait, wait. There it is. Behaviors is redux behavior. All right, let's try that again. Monica, add friend. We have one friends, right? Now we can't see the friends right now. We're not displaying our friends list, but we can sort of tell the things are working because as I'm adding friends to that array, it is updating our friend count. So the last thing I'm going to do is just create a friend list element that'll display all the friends as we add them. So we will grab our two imports from our previous elements. Create a new one called friend list. This one will be pretty simple. So the friend list, just like we did with the friend counter and its properties object, we will say, hey, I would like to have friends object. The type is array. The state path is friends. I want to make sure to include our behaviors. Here, behaviors. Redux behavior. That is going to hook us up to the Redux store. And then the last thing I'm going to do is create a UL and then a little template with a DOM repeat. Template is equals DOM repeat. We'll say that the items that we're going to pass in, again, note we're using a one-way binding here. The items is going to be friends and we will say, we will rename each item to just friend, like so. And then I'm going to create a little list item like that and I will pipe in the friend. Okay, save that. Go back to our index file. Uncomment the friend list. Go back here, refresh the page so we don't see anything just yet. We'll add a friend, we add Monica. Boom, there we go. One friend, two friends, three friends. Cool, so now we've got three elements. They are all receiving data from our global data store but the nice thing is those three elements do not have to talk directly to each other or anything like that. They all work in essentially the same way. They all take part in the unidirectional data flow. So all any of them have to do, if they want to change something, is they just dispatch an action and then we implement that action as part of our reducer. That updates the state for the app and then everyone displays the new value. So that about covers it for today. I know this was a pretty quick and dirty introduction to using Redux and Polymer and there's probably a bunch of questions that you have and a bunch of things that you would like to see. So please, please, please leave some comments down below and I will try to maybe tackle some of those feature requests and whatnot in the next episode. I definitely want to keep exploring some of this, looking at how we can share actions, do asynchronous actions, other cool things like that. As always, you can also contact me on a social network of your choosing. Thank you so much for watching and I'll see you next time. Hey folks, what's up? It is Rob. Thank you so much for watching this episode. If you'd like to see some more, we got some over there in the playlist and as always, you can click the little subscribe button to keep getting content every time we push it up to the channel. Again, thank you so much for watching.