头图

Redux 核心

是js的状态容器 提供可预测化的状态管理

  • actions:
  • reducers:
  • store

使用步骤,以计数器为例

<button id="inc">增加</button>
<span id="count"></span>
<button id="dec">减少</button>
  1. 创建store对象
    var store = Redux.createStore(reducer)
  2. 创建reducer函数, 给定默认初始状态,并匹配action

    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. 定义action

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

    store.dispatch(increment)
  5. 订阅store变化,同步视图变化

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

react-redux

  1. Provider组件
    必须位于想要共享状态的组件的顶层,将组件包裹,用于提供store,全局可用

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

    • 提供state到指定组件的props映射,同时将store的dispatch方法也放入了props中
    • 帮助我们订阅store,当store状态发生改变的时候,重新渲染组件
    • 可以通过传递第二个参数,用来简化视图中的dispatch代码
    // 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方法
    将多个reducer文件拆分后,使用redux提供的combineReduver方法进行合并reducer

Redux 中间件

本质就是一个函数,允许我们扩展redux应用程序. 由于没有应用中间件的redux,只能触发同步的action,因此如果需要使用异步的action,就需要用到中间件。比如说redux-thunkredux-saga等,这些中间件就可以让我们使用异步代码。
image.png

开发Redux中间件

模板代码

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

reducer中,需要使用redux提供的applyMiddleware方法。中间件执行的顺序就是调用这个方法是,传递过去的顺序。执行完了中间件的操作,才能继续执行reducer,

// 模拟实现
/**
 * 中间件函数
 * 执行完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处理异步操作

Redux-thunk

模拟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可以直接使用,

Redux-saga
  1. 处理异步逻辑

redux-actions

  1. createAction 创建action,不再需要声明字符串等,内部做了获取type,以及payload的操作
export const increment = createAction("increment")
export const decrement = createAction("decrement")

如此,便可在reducer中直接使用 signup 也可直接通过 bindActionCreators 包裹后的dispatch直接调用

  1. bindActionCreators将所有的action保存起来,返回一个包含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用于简化reducer的创建

    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)

终极简化 @reduxjs/tooltik

reduxjs官方的工具集

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 粉丝

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