Redux, some examples

An example reducer:

// reducer.js
const INITIAL_STATE = {
    status: "INITIAL",
    posts: []    
}
const reducer = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case "FETCH_POSTS":
            return {
                status: "FETCHING",
                ...state,
            }
        
        case "FETCH_POSTS_SUCCESS":
            return {
                status: "FETCHED",
                posts: action.payload.posts,
                ...state
            }
            
        default:
            return state;
    }
    

A component that is "connected to the redux-store":

// component.js
import React from "react";
import { connect } from "react-redux";

const PostList = props => {
    return <Posts posts={props.posts} />
}

// mapStateToProps (or whatever name you give it) is what we call a selector.
// It "grabs" the state from our reducer and returns part of that state as is, or 
// does some form of computation.

// Selectors are THE place where you want to do computation.

const mapStateToProps = (state, ownProps) => {
    return {
        posts: state.posts
    }
}

// Here we connect our component to the redux store
export default connect(mapStateToProps)(PostList); 

Sometimes you may need to have multiple versions of a certain collection. A collection of posts, and a collection of posts that are filtered by a keyword.

One might be inclined to add another piece of state on the reducer like so:

const reducer = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case "FILTER_POSTS":
            return {
                posts: state.posts,
                filteredPosts: state.posts
                    .filter(post => post.title === action.searchTerm)
            }
    }
}

// In component

const mapStateToProps = state => {
    return {
        posts: state.posts,
        filteredPosts: state.filteredPosts
    }
}

This is not ideal as we are storing the filtered posts twice. One time under "posts" and one time under "filteredPosts". So we have duplication. This is problematic, for example when the author of the post has changed his name. When we update all the posts under the posts-key, we would still have a list of posts under filteredPosts with the old author name.

A better way to handle this, would be to store the ids of the filtered posts rather than a copy of the filtered posts.

const reducer = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case "FILTER_POSTS": {
            const filteredPostsIds = state.posts
                .filter(post => post.title === action.searchTerm)
                .map(post => post.id);
                
             return {
                posts: state.posts,
                filteredPostIds: new Set(filteredPostIds)
            }
        }

    }
}

// in component

const mapStateToProps = state => {
    return {
        posts: state.posts,
        filteredPosts: state.posts
            .filter(post => state.filteredPostIds.has(post.id))
    }
}

This way you avoid redundancy. There is now only one source of truth for the posts, the posts-array in our reducer.

You are encouraged to always research if a property can be computed/derived based on other properties before storing an additional piece of state in your reducer.

Last updated

Was this helpful?