Redux

150 阅读2分钟

Redux

状态管理的东西还是挺多的,所以分成几个步骤去理解

store 说明: 状态管理,状态管理,所以必须要有一个仓库对象,先看一下这个对象的结构

{
    dispatch,    // 更改state
    subscribe,   // 监听state变化
    getState,    // 数据
    ... // 个人觉得这几个不重要
}

reducer

function reducer(state = initState, action) {
    // 接受state, action,更新state
    if (action.type === 'demo') 
    return {
        ...state,
        value: 'val'
    }
}

createStore 说明: store由这个创建;

function createStore(reducer, preloadedState, enhancer) {
    
    // 中间件, 后面说明
    if (typeof enhancer !== 'undefined') enhancer(createStore)(reducer, preloadedState)
    
  
    let currentReducer = reducer
    let currentState = preloadedState
    let listeners = [] // 监听state变化的回调
  
    function getState() {
      return currentState
    }

    // subscribe 返回一个 unsubscribe 函数,用来删除这个回调
    function subscribe(listener) {
      // listeners.push(listener)
  
      // 删除回调
      return function unsubscribe() {
        const index = listeners.indexOf(listener)
        listeners.splice(index, 1)
      }
    }

    // 更改 state 的唯一方式
    function dispatch(action) {
        currentState = currentReducer(currentState, action)
        // 触发回调
        for (let i = 0; i < listeners.length; i++) {
            const listener = listeners[i]
            listener()
        }
    
        return action
    }
  
    // 执行 reducer 初始化state
    dispatch({ type: INIT })
  
    return {
      dispatch,
      subscribe,
      getState,
      ...
    }
}

combineReducers 说明: 项目数据多需要拆分模块, 通过combineReducers,将多个reducer组合成一个;

/*
    {
        key1: reducer1,
        key2: reducer2,
        key3: reducer3,
    }
    {
        key1: reducer1(state = {}, action)
    }
*/
const combineReducers = reducers => {
    return (state, action) => {
        const nextState = {}
        for (const key in reducers) {
            if (Object.hasOwnProperty.call(reducers, key)) {
                const reducer = reducers[key]
                nextState[key] = reducer(state[key], action)
                
            }
        }
        return nextState
    }
}

Provider 说明:有了这个 store 自然就需要应用到系统中;

// <Provider store={store} />
class Provider extends Component {
    constructor(props) {
      super(props)
      const { store } = props
      // Provider 的state
      this.state = {
        reduxState: store.getState(),
        store
      }
    }
  
    componentDidMount() {
      this.subscribe() // 注册监听, state更改的时候重新渲染应用
    }
  
    componentWillUnmount() {
      if (this.unsubscribe) this.unsubscribe() // 取消监听
    }
  
    subscribe() {
        // 更改state重新渲染应用
        this.unsubscribe = store.subscribe(() => {
            this.setState(() => ({ reduxState: store.getState() }))
        })

        // 如果在componentDidMount之前就dispatch了,需要重新渲染一遍应用
        if (store.getState() !== this.state.reduxState) {
            this.setState({ reduxState: store.getState() })
        }
    }
  
    render() {
      return (
        // 传递给 connect
        <ReactReduxContext.Provider value={this.state}>
          {this.props.children}
        </ReactReduxContext.Provider>
      )
    }
}

connect 说明: 你自己的组件肯定不能每个都通过获取 ReactReduxContext,所以需要一个高阶组件帮你包一下

const connect = (mapStateToProps) => (WrappedComponent) => {
    class Connect extends Component {
      
      constructor () {
        super()
        // 传递给子组件,state变化时,触发重新渲染
        this.state = { childProps: {} }
      }
  
      componentWillMount () {
        const { store } = this.context 
        this._updateProps()
        // 监听state变化
        store.subscribe(() => this._updateProps())
      }
  
      _updateProps () {
        const { store } = this.context 
        this.setState({
          childProps: {
            ...mapStateToProps(store.getState(), this.props),
            dispatch: store.dispatch,
            ...this.props
          }
        })
      }
  
      render () {
        return <WrappedComponent {...this.state.childProps} />
      }
    }

    return Connect
}

compose 说明: 聚合函数,作用就类似洋葱模型一样;

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)))
}

enhancer 说明:利用中间件,强化你的 dispatch;

// applyMiddleware(...middlewares)(createStore)(reducer, initState)
function applyMiddleware(...middlewares) {
    return createStore => (...args) => {
      // 1. 创建 store
      const store = createStore(...args)
      let chain = []
      // 2. 每个中间件都应该有这两个函数
      const middlewareAPI = {
        getState: store.getState,
        dispatch: (...args) => dispatch(...args)
      }

      // 3. 给中间件传递参数
      chain = middlewares.map(middleware => middleware(middlewareAPI))

      // 4. 最终强化的 dispatch
      dispatch = compose(chain)(store.dispatch)
     
      return {
        ...store,
        dispatch
      }
    }
}

middleWare 说明: 中间件的固定写法,如下是最经典的thunk的源码;

({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') return action(dispatch, getState)

    // 直接的dispatch
    return next(action);
}