Reducer

What is reducer, a pure function that accepts old states and actions and returns new states

(preState,action)=>newState
Copy the code

Reducer is called because it belongs to the same type as the callback function in array.prototype. reduce(Reducer, initialValue).

It is important to keep the reducer clean and never do anything from the Reducer:

  • Modify incoming parameters
  • Perform operations that have side effects, such as API requests and route jumps
  • Call impure functions such as date.now () or math.random

compose

If a value passes through multiple functions to become another value, you can combine all the intermediate steps into a single function, which is called composition of the function.

The benefits of composition are obvious: it makes code simpler and more readable, and it makes it easier to combine other commonly used functions in different combinations, making code more expressive

/** * combinatorial functions */

function f1(arg) {
  console.log("f1", arg);
  return arg;
}

function f2(arg) {
  console.log("f2", arg);
  return arg;
}

function f3(arg) {
  console.log("f3", arg);
  return arg;
}

function compose(. funcs) {
  if (funcs.length === 0) {
    return arg= > arg;
  }
  if (funcs.length === 1) {
    return funcs[0];
  }
  return funcs.reduce((a, b) = > (. args) = >a(b(... args))); } compose(f1,f2)("omg");
// console.log(compose(f1, f2, f3)("omg"));

Copy the code

Redux

Redux is a state container for Javascript applications. It is written in pure JS to ensure consistent behavior and easy to test

Examples of Redux applications

1. You need a store to store data

2. The Reducer in the store initialized state and defined state modification rules

Commit changes to the data by dispatching an action

Actions are submitted to the Reducer function and new states are returned based on the action type

checkpoint

1. CreateStore creates a store

2. Reducer initialized and modified the state function

3. GetState Gets the status value

4. Dispatch commits the update

5. Subscribe

Handwriting redux related apis

Store (Application container)

// index.js

// import { createStore, applyMiddleware, combineReducers } from "redux";
import { createStore, applyMiddleware, combineReducers } from "./kredux";
// import thunk from "redux-thunk"; // handle asynchrony
// import logger from "redux-logger"; // Prints logs

function countReducer(state = 0, { type, payload }) {
  switch (type) {
    case "ADD":
      return state + payload;
    case "MINUS":
      return state - payload;
    default:
      returnstate; }}const store = createStore(
  // countReducer,
  combineReducers({ count: countReducer }), // Multiple reducer processes
  applyMiddleware(thunk, logger)
);

export default store;
Copy the code

Export the ES6 module

// index.js

import createStore from "./createStore";
import applyMiddleware from "./applyMiddleware";
import combineReducers from "./combineReducers";

export { createStore, applyMiddleware, combineReducers };
Copy the code

CreateStore (Create container)

export default function createStore(reducer, enhancer) {
  // Perform the following if middleware exists
  if (enhancer) {
    return enhancer(createStore)(reducer);
  }
  // If the initial state is undefined, it can be passed in by the user
  let currentState;
  let currentListeners = [];

  // get
  function getState() {
    return currentState;
  }

  // set
  function dispatch(action) {
    currentState = reducer(currentState, action);
    // State changes to execute subscribed functions
    currentListeners.forEach(listener= > listener());
  }

  // Subscribe and unsubscribe should come in pairs
  function subscribe(listener) {
    currentListeners.push(listener);
    // Return a function to remove listeners from currentListeners
    return () = > {
      const index = currentListeners.indexOf(listener);
      currentListeners.splice(index, 1);
    };
  }

  // Execute dispatch to set the initial value
  dispatch({ type: "REDUXXXXXXXXXXXX" });

  return {
    getState,
    dispatch,
    subscribe
  };
}

Copy the code

applyMiddleware

import compose from "./compose";

export default function applyMiddleware(. middlewares) {
  return createStore= > reducer= > {
    / / store
    const store = createStore(reducer);

    // Regular dispatch
    let dispatch = store.dispatch;
    // Enhanced dispatch
    let midAPI = {
      getState: store.getState,
      // Each middleware has its own scope
      dispatch: (action, ... args) = >dispatch(action, ... args) };// Execute middleware array
    const middlewareChain = middlewares.map(middleware= > middleware(midAPI));

    // Execute sequentially with the compose composition function to get the enhanced dispatchdispatch = compose(... middlewareChain)(store.dispatch);return { ...store, dispatch };
  };
}

Copy the code

CombineReducers (Combine multiple reducers into a single reducer)

export default function combineReducers(reducers) {
  return function combination(state = {}, action) {
    let nextState = {};
    let hasChanged = false;
    for (const key in reducers) {
      constreducer = reducers[key]; nextState[key] = reducer(state[key], action); hasChanged = hasChanged || nextState[key] ! == state[key]; }// Change the reducer dynamically
    hasChanged =
      hasChanged || Object.keys(nextState).length ! = =Object.keys(state).length;
    return hasChanged ? nextState : state;
  };
}

Copy the code

Story – thunk middleware

The middleware handles cases where the dispatches of the scenario are functions, such as asynchronous logic

// Write a thunk by hand to handle asynchronous thunk
export default function thunk({ getState, dispatch }) {
  return next= > action= > {
    // Next is compose() in applyMiddlerware
    // Action is equivalent to dispatch
    if (typeof action === "function") {
      return action(dispatch, getState);
    }
    return next(action);
  };
}
Copy the code

Story – logger middleware

Print log

// Write a logger by hand and print the log
export default function logger({ getState, dispatch }) {
  return next= > action= > {
    console.log("-- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
    console.log(action.type + "Executed.");
    const preState = getState();
    console.log("pre state", preState);

    const returnValue = next(action);
    const nextState = getState();

    console.log("next state", nextState);

    console.log("-- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
    return returnValue;
  };
}

Copy the code

The last complete code address is github