As the data you store in your state gets more extensive, logic can begin to creep into your components or into your connect function. In this video, discover how to fix this by making use of selectors, which are functions that extract all this logic and simplify your component files.
- [Instructor] In a previous section, we saw how to add Redux to a React application, as well as how to connect our components to it so that they could get access to the data in the Redux store, and dispatch Redux actions. And this relieved our components of the need to manage their own state, as well as made it much easier to share state between our components. We also saw how to use Thunks to remove side effect logic from our components. So, a main theme so far with our React ecosystem tools has been the separation of concerns. We want our components to worry about displaying the data we give them, we want our reducers to worry about making changes to the state, and we want our Thunks to handle all of the side-effects logic and sever communication. And so far, we've done a pretty good job of insuring the separation of concerns, but there are still one or two things that are a little bothersome, and they might not be obvious at first. Let's take a look at the mapStateToProps function for our components, and specifically how it's getting the data from the state by referring exactly to how certain data is stored in the state. At first glance, this might seem pretty harmless, and most of the time it is, but here's the problem. Getting the data we need from the state in this way requires our components, and more specifically our mapStateToProps function, to have an intimate knowledge of how our data is stored in the state. Now this might not quite make sense with the way the state is set up right now, but to show you an example, let's imagine something for a minute. Let's imagine that instead of storing our todo data directly in state.todos, and our isLoading data in state.isLoading, as we've been doing, we want to incorporate the isLoading property into the todos reducer, and move the actual todos data into state.todos.data. This is something that we can absolutely do, and I've seen it done in many React applications. But the problem here comes up if we have multiple components that were all referencing state.todos and state.isLoading directly, because now we have to go through and change all of them to reflect our changes to how our data is stored. What we could do instead is, rather than referring directly to state.todos.data or state.todos.loading, or whatever it is that we're trying to pull out of the state, we create some simple functions called getTodos and getTodosLoading, and we use these functions in the mapStateToProps for all our components. If we had created and used these functions from the start, incorporating the isLoading property into our todos reducer, and moving the actual todos array into todos.data, or making any other modifications to how our data is stored in the state for that matter, all of this would be a simple one line change. So at first it might seem a little silly to go through the trouble of creating separate functions just to avoid difficulties when doing something simple like changing state.todos to state.todos.data. After all, that would be easy enough to do just by doing a global find and replace in our project. But actually, selectors are part of something bigger. Here's what I mean. Oftentimes, we want to pass our component's data that requires a little bit of computation to obtain. For example, if we had separate to-do lists for the todos that were completed, and todos that were incomplete, this would require either our components or our mapStateToProps to include filtering logic. Neither of which is ideal, since it adds unnecessary complexity to our component files. And this all is another reason that selectors exist: to give us a place to put the logic for transforming data in the store into data our components can use. In the case I just described, we could simply have selectors called getCompletedTodos and getIncompleteTodos, each of which contains the logic necessary for filtering all the todos in the Redux store into specific sub-lists. And then we could use these selectors in our mapStateToProps instead of putting the actual logic itself there. We'll look into this in more detail in coming videos.
- Building more maintainable and robust React applications
- Installing React and other tools
- Adding Redux
- Dealing with side effects
- Libraries for dealing with side effects
- Styling React apps more effectively with styled-components
- Using React hooks
- React fragments
- Testing Redux, Redux-Thunk, Reselect, and styled-components