头图

Redux core

is a state container for js that provides predictable state management

  • actions:
  • reducers:
  • store

Use steps, take counter as an example

<button id="inc">增加</button>
<span id="count"></span>
<button id="dec">减少</button>
  1. Create store object
    var store = Redux.createStore(reducer)
  2. Create a reducer function, given a default initial state, and matching actions

    function reducer(state = initState, action) {
      switch (action.type) {
     case 'increment':
       return {
         ...state,
         count: state.count + 1
       }
     case 'decrement':
       return {
         ...state,
         count: state.count - 1
       }
     default:
       return state
       break
      }
    }
  3. define action

    var increment = { type: 'increment' }
    var decrement = { type: 'decrement' }
  4. trigger action

    store.dispatch(increment)
  5. Subscribe to store changes, synchronize view changes

    store.subscribe(() => {
      console.log(store.getState())
    })

react-redux

  1. Provider assembly
    Must be at the top level of the component that wants to share state, wrap the component to provide a store, available globally

    <Provider store={store}>
     <Children>
    </Provider>
  2. connect method

    • Provide the props mapping from the state to the specified component, and put the dispatch method of the store into the props
    • Help us subscribe to the store and re-render the component when the state of the store changes
    • Can be used to simplify dispatch code in the view by passing a second parameter
    // counter.js
    import React from 'react'
    import { connect } from 'react-redux'
    import { increment, decrement } from '../store'
    const Counter = ({ count, inc, dec}) => {
      return (
     <>
       <button onClick={inc}>+</button>
       <span>{count}</span>
       <button onClick={dec}>-</button>
     </>
      )
    }
    
    
    const mapStateToProps = state => ({
      a: '10099',
      count: state.count
    })
    // 映射dispatch 方法
    const mapDispatchToPrps = dispatch => ({
      inc() {
       dispatch(increment)
      },
      dec() {
       dispatch(decrement)
      }
    })
    // connect的两个方法, 第一个映射state到props,第二个 映射dispatch到props中,可以减少视图代码
    export default connect(mapStateToProps, mapDispatchToPrps)(Counter)
    
  3. combineReducer method
    After splitting multiple reducer files, use the combineReduver method provided by redux to merge reducers

Redux middleware

The essence is a function that allows us to extend the redux application. Since redux without middleware can only trigger synchronous action , if you need to use asynchronous action , you need to use middleware. For example, redux-thunk , redux-saga , etc. These middleware allow us to use asynchronous code.
image.png

Developing Redux middleware

template code

export const middleware = store => next => action {
    next(action)
}

reducer , you need to use the redux method provided by applyMiddleware . The order in which the middleware is executed is to call this method, passing the order in the past. After the operation of the middleware is completed, the reducer can continue to be executed.

// 模拟实现
/**
 * 中间件函数
 * 执行完middlewares, 然后需要返回最初的需要执行的reducer
 * @param  {...any} middlewares
 * @returns
 */
function applyMiddleware(...middlewares) {
  // 调用enhancer的时候,传进来的createStore
  return function(createStore) {
    // enhancer函数传递过来的reducer, preloadState
    return function(reducer, preloadState) {
      // 创建一个store, 将用于返回我们自定义的增强型的store,实际上中间件只需啊哟对dispatch进行增强后返回
      const store = createStore(reducer, preloadState)
      // 保存新建的store里的函数
      const middlewareAPI = {
        getState: store.getState,
        dispatch: store.dispatch
      }
      // 调用中间件的第一层函数, 执行中间件最外层的函数, 这里需要将传递一个没有disptch的store对象给下一层级使用
      let chain = middlewares.map(middleware => middleware(middlewareAPI))
      // 将创建的dispatch进行重写, 获取到最后的dispatch, 等待action命令. 按照设计,先注册的先执行.
      let dispatch = compose(...chain)(store.dispatch)
      return {
        ...store,
        dispatch
      }
    }
  }
}
function compose() {
  let funcs = [...arguments]
  return function(dispatch) {
    // 倒序执行funcs, 因为该函数返回的就是最后一个dispatch
    for (let i = funcs.length - 1; i >= 0; i--) {
      dispatch = funcs[i](dispatch)
    }
    return dispatch
  }
}

Redux handles asynchronous operations

Redux-thunk

mock thunk


/**
 * 处理异步操作
 * @param {*} store
 * @returns
 */

const thunk = ({dispatch}) => next => action => {
  // 处理异步操作, 异步操作的action需要返回一个函数,这个函数的参数就是dispath
  if (typeof action === 'function') {
    return action(dispatch)
  }
  // 同步操作不受影响
  next(action)
}
export default thunk
// actions中,
// 使用thunk中间件调用这个方法名 需要返回一个接收dispatch的函数,
// 通过这个dispatch来接收异步操作的结果,
// 然后触发同步的action,同时将值传递过去
export const increment_async = payload => dispatch => {
  setTimeout(() => {
    dispatch(increment(payload))
  }, 2000);
}

redux-thunk can be used directly,

Redux-saga
  1. Handling asynchronous logic

redux-actions

  1. createAction Create an action, no need to declare a string, etc., and internally do the operation of obtaining type and payload
export const increment = createAction("increment")
export const decrement = createAction("decrement")

In this way, signup can be used directly in the reducer, or it can be called directly through the dispatch packaged by bindActionCreators

  1. bindActionCreators saves all actions and returns an object containing the action

    
    import React from 'react'
    import { connect } from 'react-redux'
    import { bindActionCreators } from "redux"
    import * as counterActions from '../store/actions/counter.action'
    const Counter = ({ count, increment, decrement, increment_async}) => {
      return (
     <>
       <button onClick={() => increment(6)}>+</button>
       <span>{count}</span>
       <button onClick={() => decrement(5)}>-</button>
     </>
      )
    }
    
    const mapStateToProps = state => ({
      count: state.counter.count
    })
    
    
    const mapDispatchToPrps = dispatch => (bindActionCreators(counterActions, dispatch))
    
    export default connect(mapStateToProps, mapDispatchToPrps)(Counter)
    
  2. handleActions for simplifying reducer creation

    import { handleActions as createReducer } from "redux-actions";
    import { increment, decrement } from "../actions/counter.action";
    
    const initState = {
      count: 0
    }
    
    export default createReducer({
      [increment]: (state, action) => ({ count: state.count + action.payload}),
      [decrement]: (state, action) => ({ count: state.count - action.payload})
    }, initState)

Ultimate simplification @reduxjs/tooltik

Reduxjs official toolset

configureStore(): wraps createStore to provide simplified configuration options and good defaults. It can automatically combine your slice reducers, adds whatever Redux middleware you supply, includes redux-thunk by default, and enables use of the Redux DevTools Extension.
createReducer(): that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses the immer library to let you write simpler immutable updates with normal mutative code, like state.todos[3].completed = true.
createAction(): generates an action creator function for the given action type string. The function itself has toString() defined, so that it can be used in place of the type constant.
createSlice(): accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
createAsyncThunk: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches pending/fulfilled/rejected action types based on that promise
createEntityAdapter: generates a set of reusable reducers and selectors to manage normalized data in the store
The createSelector utility from the Reselect library, re-exported for ease of use.

路飞的笑
119 声望3 粉丝

人活着就要做有意义的事情。