Introduction to the

The core API of Redux includes CombinerCreators, createStore, applyMiddleware, bindActionCreators, and Compose. BindActionCreators is currently unavailable and will be updated later.

Start with actions and actionType

// actionType/constant.js
export const ADD_TODO = 'ADD_TODO';
export const MODIFY_TODO = 'MODIFY_TODO';
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';

// actions/todo.js
import * as constant from '.. /actionType/constant';

export default {
  addTodo: text= > {
    return {
      type: constant.ADD_TODO,
      id: parseInt(Math.random().toString().slice(-5)),
      text
    }
  },
  modifyTodo: (id, text) = > {
    return {
      type: constant.MODIFY_TODO,
      id,
      text
    }
  },
};


// actions/index.js
import todo from './todo';
import visiblilityFilter from './visiblilityFilter';

export default {
  todo,
  visiblilityFilter,
}
Copy the code

createStore

CreateStore is a function that creates a store. The first reduce argument is required, and the initalState and Enhance arguments are optional. This is a simple implementation, no error handling, and is actually treated as enhance when the second argument is a function. InitalState is undefined, and can be specified on lines 82-85 of redux-createstore.

CreateStore returns an object with attributes getState, Dispatch, subscribe, add subscribed callbacks to the listener list, Callbacks in the Listener are performed after each Reducer state update), they are functions.

Bug: createStore does not pass initalState, state defaults to empty object, Redux source code, even if initalState is not passed, the store is not empty object. Need to fix.

// lib/redux/createStore
export default function createStore(reducer, initalState, enhance) {
  let state = initalState || {},
    listeners = []
  const getState = () = > {
    return state
  }
  const dispatch = (action) = > {
    state = reducer(state, action)
    listeners.forEach(fn= > fn())
  }
  const subscribe = (fn) = > {
    listeners.push(fn)
    return () = > {
      unsubscribe(fn)
    }
  }
  const unsubscribe = (listener) = > {
    let index = listeners.indexOf(listener)
    if (index === -1) {
      listeners.splice(index, 1)}}return {
    getState,
    dispatch,
    subscribe,
  }
}
Copy the code

combineReducers

Merge multiple reducers into one reducer, similar to Object.assign. The key below can be understood as the id of the submodule

// lib/redux/combineReducers.js
/* reducerObj equals * {* todos, * visibilityFilter, *} */
export default function combineReducers(reducerObj) {
  return function (state = {}, action) {
    const keys = Object.keys(reducerObj);
    const newState = {}
    keys.forEach(key= > {
      // Key equals todos and reducer equals reducers in todos.js
      const reducer = reducerObj[key]
      newState[key] = reducer(state[key], action)
    })
    return{... state, ... newState } } }// reducers/index.js 
// import { combineReducers } from 'redux'
import { combineReducers } from '.. /lib/redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'

const todoApp = combineReducers({
  todos,
  visibilityFilter,
})

export default todoApp
Copy the code

createReducer

To resolve the Switch branch in the Reducer, accept the initialState and Handlers objects and return a Reducer

// lib/redux/createReducer
const createReducer = (initialState, handlers) = > {
  return (state = initialState, action) = > {
      if (handlers.hasOwnProperty(action.type)) {
          return handlers[action.type](state, action);
      }
      return state;
  };
};
export default createReducer;
Copy the code

applyMiddleware

To record the state before and after the reducer, you can use Middleware to enhance dispatch (why Dispatch? A reducer is a reducer and a reducer is a reducer. A reducer is a reducer and a reducer is a reducer. . Enhanced Dispatches that can be modified, such as printing an action every time a dispatch is printed.

const __dispatch = store.dispatch
store.dispatch = (action) = > {
 	console.log('action: ', action);
  __dispatch(action);
} 
Copy the code

Think about the inconvenience of saving old dispatches and rewriting them every time you use middleware. Let’s redefine middleware as follows:

const middleware =  (store) = > (dispatch) = > (action) = > {
   // do what you want
  dispatch(action);
  // do what you want
};
Copy the code

Two simple middleware:

// Just print Action
const loggerAction = (store) = > (dispatch) = > (action) = > {
  console.log('action: ', action);
  dispatch(action);
};

// Only the updated state is printed
const loggerState = (store) = > (dispatch) = > (action) = > {
  console.log('current state: ', store.getState());
  dispatch(action);
  console.log('next state: ', store.getState());
};
Copy the code

Now implement applyMiddleware. ApplyMiddleware is a combination of middleware, and forEach takes care of it.

Store = applyMiddleware(Store, funcArr)

// lib/redux/applyMiddleware
const applyMiddleware = (store, middlewares) = > {
  let dispatch = store.dispatch;
  middlewares.forEach((middleware) = > {
      dispatch = middleware(store)(dispatch);
  });

  return {
      ...store,
      dispatch,
  };
};

export default applyMiddleware;

// src/todoDemo/index.js 
// Each dispatch will print current state and action first, and print next state after reducer, referring to Koa onion ring model
store = applyMiddleware(store, [loggerAction, loggerState]);
Copy the code

compose

Given a list of functions, execute multiple functions in order

// lib/redux/compose
const compose = (. funcArr) = > {
  return funcArr.reduce((a, b) = > (. args) = >a(b(... args))); };export default compose;
Copy the code