Subtitles section Play video Print subtitles Hello, everyone. My name is Lauren Lee and my pronouns are she and her. My talk is called why I decided to modularize my ducks in the React app. We will talk about good and bad of React, explore some of the problems within Redux and I will introduce and propose one possible solution. That solution is called ducks. My journey to tech was rather unconventional or non-traditional, if you will. I didn't study CS in college but instead was an English teacher for seven years before embarking on my journey learning to code. I spent a lot of time in the classroom lecturing on structure and I mean the five paragraph essay, the art of writing an outline, rules of grammar and proper sentence construction. Essentially, all things structure when it comes to a high school lit class. This combined with the fact I am a Virgo means I really like structure, specifically organized structure. At Ada developer's academy, a program that trains folks to learn to code here in Seattle my peers were giving me a hard time over my color-coded notes. In my defense, I just quit my job. I had taken this massive risk of learning to code and this sort of stuff stock markets me and brings me peace, joy and sanity. While learning to code, just like my old classroom, I loved when everything had its place. I love a thoughtful organized codebase. It genuinely makes me smile. Later on down the road when I became a software engineer at Amazon I fell really hard for React. As I am sure many of us know it has powerful features including the virtual DOM, relative quick learning curve, helper developer tools and the reusability of modularized components. I have been drawn to the components of the architecture that is the foundation of React. I am sure a lot of us are familiar with React so I won't bore by you explaining the intrinsic characteristics. But I will pause for the moment. When you build with React, you create independent and isolated reusable components and compose them together to build complex interfaces. The former grammar obsessed rule following teachers I am loves the encouraged organization and division of components this implies. Finding the reusability of -- I find the reusability of the components to be so helpful for engineers plus it always makes it easy to find everything within your code. Today, I am going to be using a React app that aggregates viewing data to create a most binged TV show app. This app can be divided the nav, the individual show, and the list view. Now, the architecture of this app is relatively straightforward, but we all know that things can get complicated really quick. Thus developers at this points are often forced to discover the not-so-glamorous parts of React. Oftentimes we will want to pass data as props around the app quite a bit and React advocates for a single directional flow and things get messy when we want data in sync when two or more components share that data. The source of truth is only in one place. React docs encourages us to lift state up. If you have two children that need to access the same data and this means putting the data in the nearest ancestor of the two components. If these two components are very far apart in the tree, the nearest ancestor could be at the top level of the component tree. To complicate things even more, the immediate components, have absolutely -- may have absolutely no use for the props it is being passed. They just happen to be stuck in the middle and have to pass it along. No, thank you. My favorite analogy for this is the idea of me wanting to tell, say, my cousin, a story but instead of being able to tell her directly that story I need to tell my aunt. That is fine if it is, you know, a little non embarrassing story but say it is about something I don't necessarily want to tell my aunt about bummer. I still have to pass it through her regardless. The top ancestor has to pass data down to several intermediary components along the way to get to the property component and just like the game telephone this creates opportunities for errors. The original story can be muddled and some can get confused as they try to trace the props that get passed between the many components. To view it another way, one state is being passed up and down and in between the component tree, and it is easy to imagine how things could get complicated and to add insult to injury, my girl Sandy Mets taught me to fear coupling and that is happening big time between components and parents to try to move a parent around would be complicated. There is coupling between the components and its parents and between the component's children that it is passing props to. Thus, to no one surprise, this impacts performance as every update made to the data causes all of the children to rerender which causes massive performance and speed issues. It is really a balancing act. There are many great things React drink brings to the table. It is important to find a solution for managing an application state if you are looking to build something more complex than a to-do list. When we are in the designing phrase of a project, we often, more often than not we want an app to be able to scale. We want to be able to create something maintainable for many months or years into the future and dare I say it be nice to maintain our sanity when it comes to state management which brings me to Redux. The state container superhero that saves our day. Remember the chaos that was the mess of passing data around our components? That is what Redux successfully helps you make sense of. Redux is a state management tool for JavaScript applications meaning I can pass data, or say the embarrassing story about my most recent Bumble escapades to my cousin without telling my aunt about it. AKA I get to avoid the chaos of that story being bounced around all the components or my many crazy uncles just to update or change one of them and this is important because of Redux's most important principle: The global store. Let's talk about that. The big thing to remember is that the entire state of the application is stored in one central location called the store meaning that each component of your React app gets to have direct access to the state of the application without having to send props down to child components or using callback functions to send data back up to a parent. That is pretty dreamy. Redux provides essential storage that can hold data from anywhere in the application. To put it differently, Redux completely eliminates the messy tunneling when you are passing data down from a parent to subcomponents and manipulating that. Today I am going to add each piece of Redux to my React app to show how that all works together. So for the app I showed you earlier, you can imagine that each color is a different React component. Currently, with just React the data in this app flows directionally as so. I want to add Redux so that the data transfer and state look more like this referring back to the Redux diagram had first thing we have to build is our store. It is crucial to remember the store in Redux is like the human brain and absolutely fundamental. The state of the whole app lives inside the store. To start playing with Redux we should create a store for wrapping up the state. Shall we all together? OK. To get started, we will create a folder and call it Redux. Within Redux we will then create a folder for the store. Within the store, we will create a file and call it index.js. Copy some code and put in there. The create store function I have here is the function for creating the Redux store. You may pass initial state to create store you don't have to most of the time although it can be useful for service side rendering, traditionally the state comes from the reducers which is what I will do here as it takes the reducer as the first argument, root reducer in our case. Wait. I haven't explained what reducers do yet. I said before that state comes from the reducer what matters now is understanding what reducers do. Let's go back to our diagram. In Redux, the reducers produce the state and the state is not something you create by hand. Reducers specify how the application state changes. One of the principles of Redux is that the state is immutable and cannot change in place. In play and React the local state changes in place with function setstate. In Redux, you can't do that. A reducer is just a JavaScript function. It takes two parameters, the current state and an action, which is why the reducer must be pure meaning that it returns the exact same output for the given input. Creating a reducer is actually pretty simple. So let's do that all together. I will pick up where I left off and create another folder and call it reducers. Within reducers a file index.js. Pop in this code. Great. The reducer here is sort of a silly one. Oh, I am not on the slide. This reducer here is sort of a silly one in that it returns the initial state without doing anything else but definitely notice how the initial state is passed as the default parameter. OK. We have seen that? Good. Now, reducers are without a doubt the most important concept in Redux. Let me say it again. Reducers produce the state of the application but this should then beg the question how does a reducer know when to produce the next state? Well, that is where actions come in. One of the principles of Redux is that the only way you can change the state is by sending a signal to the store, the signal is an action and how do you change immutable state? You don't. Resulting state is a copy of the current state plus the new data. You may be thinking whoa, Lauren, that is a lot of data to know, but the reassuring thing is that Redux actions are nothing more than just JavaScript objects. This is an example of what one might even look like. OK. You know the drill. Let's create a simple action all together. Again, we will create a folder. Actions. File index.js and prop -- plop in it add show here. Today I think it will be fun to add the functionality of adding a show. Every action requires a type property for describing how the state should change and it is really just a string. The reducer uses that string to determine how to calculate the next state and you can specify a payload, just as I did, if you would like. In my example, the payload is a new show. OK. Back to the diagram. Since types are just strings and strings are as we know prone to typos and duplicates it is better to have action types declared as constants. It is best practice to wrap every action within a function which helps to avoid errors. Let's also do that quickly and create a simple action creator all together. Again, constants within constants, a file, and quite simple there. Next up, I want to open up my actions folder and I am going to now use what we just created. I will remove the quotes and of course I will have to import it from a local directory. From, I think, I called it constants/action-types. Great. Now we are using that. You all still with me? No? OK. If not, I think it would be important to take the time before we go any further to just quickly recap the main Redux concepts we just implemented. The Redux store is in charge of orchestrating all of the moving parts. All of the state lives in a single immutable object and as soon as the store receives an action it triggers as a reducer and the reducer then returns to next state. The order sort of goes like this, an action first occurs within a component, say someone trying to add a show, or maybe filter the view, see the details or delete a component even, then that calls the action into action type which grabs the particular reducer that will update and modify the state, and once that state is changed, the view is rerendered and that is how Redux works. Congrats. You now know everything there is to know about how to add Redux to a React app. You should feel ready to scale it to an app on your own except... you may have noticed that while we were setting up our basic, very simple beginning other Redux app, we had to create a bunch of folders and files. OK. Imagine this. You decide to add all of the functionality a traditional app has beyond just adding a show maybe you want to filter and edit and delete it. Whatever it is. If we continue down this path, it would be easy to imagine how things could be messy or complicated or confusing quickly because you will then have to edit the constants in one file, the reducers in another, the action creators in another, and yet again go back and edit the actions so you are pretty much playing tennis, emotionally, physically, everything, match over here because just to add one single, small piece of feature functionality equates to editing and adding several different files. This kind of just gives me a headache. This is a way of organizing your Redux by type and that is essentially the most common but you end up jumping back and forth for files related to a single piece of functionality because the constants action creators are imported to the reducer file and the action creator are imported into the container to be dispatched and all that becomes a little annoying, wouldn't you agree? What I found to be really wild was that there is actually no prescribed one way of organizing our Redux files. This by-type method, yes, is super common, and it is taught in a ton of tutorials but it is obviously sort of flawed. My theory is oftentimes when you are first learning about Redux and the roles of actions and reducers you start off with a really simple example. Most tutorials don't take you to the next level but if you are building something with React and Redux that is more complicated than a to-do list you realize quickly you may need a smarter way of scaling your codebase over time. These actions, constants and reducer are all related but exist in the fractured state and switching back and forth from file to file only takes a few seconds. I am going to give you that but it can make my head fuzzy and simply put I find it hard to maintain. Thus, yet again, all my English teacher organizational habits came rushing back to me and I knew there had to be a way to be strategic and thoughtful with the organization of my codebases architecture. I dug into the research on Medium articles knowing there must be something out there that would offer peace of mind and I was right. There are a lot of ideas out there about it. Some people suggested online a solution to the frustration might be to organize your code by feature as encapsulating the component and store into a single folder following the React component concept. This means you would have to tie a slice of the Redux store to a container and that is counterintuitive to the core of what Redux promotes. Bangladesh to the drawing board I went and further research led me to discover the moment you have been waiting for based on the title of this talk ducks to the rescue. What are ducks? Erik Rasmussen kept needing to add tuples and such for each use case and was keeping them in separate files and folders, however, 95% of the time, it is only one reducer and action pair that ever needs their associated action thus it makes more sense for all the pieces to be bundled into isolated modules that can self-contained and packaged easily into a library. Ducks is a proposal for bundling reducers, action types and actions into the same file. Why would this be the solution to our problem or why get excited about ducks? Beyond their adorableness factor. Ducks seek to solve the issue of the toggled back and forth repeated feature of splitting up. We can repackage it into the Redux modules. Let's get to the fun part and convert or Redux to ducks, shall we? Great. Rhetorical, yes, I suppose. Remember, our example was trying to create the functionality of adding a show and together right now we are going to move the action types, actions and reducers all into one file. We will make a folder call it ducks. You can call it module but for the fun of it today it will be ducks in a file. Let's first grab from the action type -- the constants. Let's delete and pull it into our new file and we will add export const and we will have to add action types here and add show. Great. Oh, hello. OK. And let the deleting begin. We get to now delete the constants folder. Fantastic. Next up is actions. We will grab from the actions and bring it into our new file. Here we will add actions= this and don't forget you now get to delete the actions folder. Bye, actions. And last we get to merge in and handle the reducer. We will grab all this code and bring it over to the ducks. This part is the code that loads the initial state and that will stay as it is. I think I want to change this reducer here because currently it does nothing, as I said, other than returning the initial state and we can fix that actually, pretty easily, by turning it into a switch statement which I have right here. Last but not least, let us delete the reducer's folder. OK. Everyone, right here, in 21 lines of code officially contains all the functionality we built up before. It runs exactly the same way but it is modularized into a clean doc or ducks for optimized state management. Remember when we created all of those folders and all these files and it looked something like this, messy, messy, messy. They were fragmented and separated from one another. Compare that mess that that was to this new file which contains all of the same capability in a legible fashion and I will call that a win. Hopefully, you do too! In fact, such a little amount of code that it is able to fit into a single-slide right here. I have to say it was pretty easy and painless to create even in front of a nerve-wracking environment. That is the art of duck. The art of ducking is structure an app to become more modular. It is a sexy buzzword in this community but think about it. It is great thing because it is obvious which piece of Redux is handling rich functionality and you no longer have to scroll through masses of files before finding the one you are needing to work on but this is only one way of structuring your Redux. There are plenty of other options. The simple fact I am encouraging you to explore the ways to creatively define what structures means for you means the structure loving person I once was is leveling up to embrace ambiguity and doing whatever is best for your code is the right way. Ducks remove boilerplate and can remove a function's functionality to a reducer. I have been on dev teams who adopted this structure and we were really happy with it. Maybe you will be too. In conclusion, I hope you are walking away from this talk feeling React and Redux is not so confusing and maybe you were convinced by this duck's organization. Thank you for listening. My name is Lauren Lee and I would love to hear about your favorite organizational procedures or chat further if you have quacky proposals. Here is the original GitHub, arrest me to learn more, if you would like it. Thank you.
B1 redux state action app file data Why I Chose to Modularize the Ducks in My React App // Lauren Lee // CascadiaJS 2018 3 0 林宜悉 posted on 2020/04/15 More Share Save Report Video vocabulary