143 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| ---
 | |
| title: Redux Selectors
 | |
| ---
 | |
| 
 | |
| ## Redux Selectors
 | |
| 
 | |
| Redux selectors in their essence are functions that are used to select a subset of data from a Redux state, or in Redux terms, calculate derived data.
 | |
| 
 | |
| These functions take a state as an argument and make some computations and then return the data that is going to be passed down to any given component.
 | |
| 
 | |
| 
 | |
| ## Why use this pattern
 | |
| 
 | |
| One reason for using this pattern is to avoid duplicate data.
 | |
| 
 | |
| Given that we have a list of items in Redux, and we only need to show a filtered list. 
 | |
| 
 | |
| A naive approach with Redux would be to filter the list, store it in Redux and then pass it along to the specific component.
 | |
| 
 | |
| With this approach we would have two copies of the items and would be easier for the data to get out of sync. 
 | |
| 
 | |
| In case of any operation on the data it would be necessary to make the update twice.
 | |
| 
 | |
| Another naive approach would be to transform the data directly in the component making use of Redux mapStateToProps like how it's shown in the code below.
 | |
| 
 | |
| 
 | |
| ```javascript
 | |
|  // reducer
 | |
|  const listofItems=(state={items:[]},action)=>{
 | |
|      switch(action.type){
 | |
|          case "SHOW_ALL":
 | |
|             return action.data.items;
 | |
|          default:
 | |
|             return state;
 | |
|      }
 | |
|  };
 | |
| ```
 | |
| The items stored could be something like:
 | |
| 
 | |
| ```javascript
 | |
| {
 | |
|     id:1,
 | |
|     text:"Lorem ipsum dolor sit amet",
 | |
|     complete:false
 | |
| }
 | |
| ```
 | |
| ```javascript
 | |
|     import React, { Component } from "react";
 | |
|     import {connect} from "react-redux";
 | |
| 
 | |
|     class ItemShow extends Component{
 | |
|         render(){
 | |
|             const {incompleteItems}= this.props
 | |
|             return (
 | |
|                 <ul>
 | |
|                     {
 | |
|                         incompleteItems.map(item=>(
 | |
|                             <li key={item.id}>
 | |
|                                 {item.text}
 | |
|                             </li>
 | |
|                         ))
 | |
|                     }
 | |
|                 </ul>
 | |
|             )
 | |
|         }
 | |
|     }
 | |
|     const mapStateToProps =(state)=>{
 | |
|         return {
 | |
|             incompleteItems:state.listofItems.filter(item=>{
 | |
|                 return !item.complete
 | |
|             });
 | |
|         }
 | |
|     };
 | |
|     export default connect(mapStateToProps,null)(ItemShow);
 | |
| ```
 | |
| With this it would make the components more coupled to the Redux state and less generic and reusable.
 | |
| 
 | |
| Also it would impact the performance of the application, because the mapStateToProps function gets called a lot during the lifecycle of the application and using it for this type of calculation is not a good practice.
 | |
| 
 | |
| ## Selector function in action
 | |
| 
 | |
| To solve the problem above a selector function is going to be created.
 | |
| 
 | |
| As per good practices, this function should be near the reducer
 | |
| 
 | |
| Expanding the example above, now the reducer would be something like the code bellow.
 | |
| 
 | |
| ```javascript
 | |
|  // reducer
 | |
|  const listofItems=(state={items:[]},action)=>{
 | |
|      switch(action.type){
 | |
|          case "SHOW_ALL":
 | |
|             return action.data.items;
 | |
|          default:
 | |
|             return state;
 | |
|      }
 | |
|  };
 | |
|  
 | |
|  const getIncompleteItems=state=>{
 | |
|      const {listofItems}=state;
 | |
|      return listofItems.filter(item=>{
 | |
|          return !item.complete
 | |
|      });
 | |
|  }
 | |
| ```
 | |
| 
 | |
| And the component would look like something like this
 | |
| ```javascript
 | |
|     import React, { Component } from "react";
 | |
|     import {connect} from "react-redux";
 | |
| 
 | |
|     class ItemShow extends Component{
 | |
|         render(){
 | |
|             const {incompleteItems}= this.props
 | |
|             return (
 | |
|                 <ul>
 | |
|                     {
 | |
|                         incompleteItems.map(item=>(
 | |
|                             <li key={item.id}>
 | |
|                                 {item.text}
 | |
|                             </li>
 | |
|                         ))
 | |
|                     }
 | |
|                 </ul>
 | |
|             )
 | |
|         }
 | |
|     }
 | |
|     const mapStateToProps =(state)=>{
 | |
|         return {
 | |
|             incompleteItems:getIncompleteItems(state);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     export default connect(mapStateToProps,null)(ItemShow);
 | |
| ```
 | |
| 
 | |
| #### More Information:
 | |
| [Simple reselect explanation](https://guide.freecodecamp.org/redux/reselect)
 | |
| 
 | |
| [reselect official documentation](https://guide.freecodecamp.org/redux/reselect)
 | |
| 
 | |
| 
 |