React Js Redux: Reducer

Once you had defined your action ( description action type), and still state is not knowing how to change, so here comes to Reducer

Design Your State Case

first you should define how and what you want to change your state

let’s use the most simple demo : increase +1 in Action

{
  type: 'INCREMENT'
}

So in Reducer, it is actually an function, which take care action had dispatch and handle state, you need to pass 2 parameters,
one is initial state, second is the action object:

function counter(state = 0, action) {
  // return state 
}

then you could handle your state inside:

function counter(state = 0, action) {
 switch (action.type) {
   case 'INCREMENT':
   return state + 1;
   default:
   return state;
 }
}

use switch to handle the difference case of state, here you use Increment which return state + 1,  or return default state

Once more example here:  add to do

First define your action:

// actions/TodoActions
export const ADD_TODO = 'ADD_TODO';
export function addTodo(text)
{
  return{
    type: ADD_TODO,
    text
  }
}

here you define action const, and you create Action Creator to return action type

so that send to reducer to change the state:

// reducers/AppReducers
import {ADD_TODO} from 'actions/TodoActions';
export function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ];
    default:
      return state;
  }
}

As you could see once again function todos is an Reducer, and you inject : initial state and action

Then go ahead to return the states by switch case:

first is ADD_TODO, return your todo text, and not completed

else return the default state

Since Reducer is return the state, so keep it simple, remember follow to avoid:

1. change the parameter

2. add any side effect event, like call API or routing change

3. And since reducer is pure function, then you should not called other not pure functions like Date.now() or Math.random()

And you could put as much reducer you want which could separate different object to change, in this way your code will be more reusable and more easy to debug:

function todos(state = [], action) {
  switch (action.type) {
    case ADD_TODO:
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case TOGGLE_TODO:
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: !todo.completed
          })
        }
        return todo
      })
    default:
      return state
  }
}

function visibilityFilter(state = SHOW_ALL, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return action.filter
    default:
      return state
  }
}

function todoApp(state = {}, action) {
  return {
    visibilityFilter: visibilityFilter(state.visibilityFilter, action),
    todos: todos(state.todos, action)
  }
}

And Redux provide an function called combinereducers() which allowed you combien those reducers :

import { combineReducers } from 'redux'

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp

Here it is the Reducer concept, hope this could help you understand the core concept