Redux

Thinking in Redux

Core conception

Describe state with normal object. Dispatch an action to update the data of state. Use some functions to connect action with state, that is reducer.

Javascript
function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter;
  } else {
    return state;
  }
}

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

Add another reducer to call the reduces above, to manage the whole state of application:

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

Principles

  • One way data flow
    • Appliction’s state is maintained in a object tree, which exists unique in stores。
  • State is only readable
    • The only way to change state is dispatch an action,which is an object to descrbie what happened.
  • Action just describe the fact that something happened, do not describe how to update the state.

Action is an object, and can be logged、serialized、stored.

Javascript
store.dispatch({
  type: 'COMPLETE_TODO',
  index: 1
})

store.dispatch({
  type: 'SET_VISIBILITY_FILTER',
  filter: 'SHOW_COMPLETED'
})
  • use pure function to modify

Action

Action is the only datasource of store. Use store.dispatch() to deliver action into store.

Use action generate function in Redux, to return an action:

Javascript
function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

Reducer

Reducers specify how changes to the application state are sent to the store in response to actions.

Reducer is pure function,with prev state and prev action as params, to return new state:

Javascript
function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state
  }
}

Split reducers

Javascript
import { combineReducers } from 'redux'
import * as reducers from './reducers'

const todoApp = combineReducers(reducers)

import { combineReducers } from 'redux'

const todoApp = combineReducers({
  visibilityFilter,
  todos
})

export default todoApp

equals to :

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

Store

Store’ works:

  • maintain states of application;
  • provide getState() to get state;
  • provide dispatch(action) to update state;
  • use subscribe(listener) to add listener;
Javascript
import {
  addTodo,
  toggleTodo,
  setVisibilityFilter,
  VisibilityFilters
} from './actions'

console.log(store.getState())

const unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

store.dispatch(addTodo('Learn about actions'))
store.dispatch(addTodo('Learn about reducers'))
store.dispatch(addTodo('Learn about store'))
store.dispatch(toggleTodo(0))
store.dispatch(toggleTodo(1))
store.dispatch(setVisibilityFilter(VisibilityFilters.SHOW_COMPLETED))

unsubscribe();

Data Flow

  • call store.dispatch(action)
  • Redux store call the incoming reducer function
  • root reducer combine chidren reducers to a single state tree。
  • Redux store mantain the root reducer to return the whole state。