React系列-Redux

redux/createStore方法返回getState、dispatch和subscribe。

  • 組件之間經過調用dispatch action,action傳入到reducer中,而後根據老的state和action生成新的狀態。監聽渲染函數數組遍歷執行
  • getState返回當前狀態state
  • subscribe函數調用將渲染函數暫存到一個數組中,並返回一個函數用來過濾掉當前綁定函數,也就是取消訂閱。
function createStore(reducer){
        let state;
        getState = () => state;
        let listeners = [];
        let dispatch = function(action){
            state = reducer(state,action);
            listeners.forEach(fn=>fn())
        }
        <!--默認狀態state-->
        dispatch({type:'@INIT'})
        let subscribe = function(fn){
            listeners.push(fn);
            return function(){
                listeners = listeners.filter(l=>l!=fn)
            }
        }
        return {
           getState,
           subscribe,
           dispatch
        }
    }
    
複製代碼

reducer

reducer自己是一個函數,傳遞兩個參數,分別爲state和action,而後判斷action.type來進行不一樣的邏輯來改變statereact

import * as Types from '../action-types'
    function counter(state = {number:0},action){
      switch(action.type){
        case Types.INCREMENT:
          return {number:state.number+ action.count}
      }
      return state;
    }
    export default counter;
複製代碼

redux/combineReducers

用來合併多個reducerredux

function combineReducers(reducers){
        return function(state={},action){
            let obj = {};
            for (let key in reducers) {
                <!--第一次進來注意state[key]爲undefined-->
                obj[key] = reducers[key](state[key], action);
            }
            return obj
        }
    }
    export default combineReducers({
      counter: counter,
      todo
    });
複製代碼

action

action就是一個包括type和payload屬性的對象數組

export default {
      add(val){
        return {type:Types.INCREMENT,count:val}
      }
    } 
複製代碼

bindActionCreators

將action包裝成自動dispatchbash

let bindActionCreators = (actions,dispatch) => {
      let obj = {}
      for(let key in actions){
        obj[key] = (...args) => dispatch(actions[key](...args))
      }
      return obj;
    }
複製代碼

react-redux

用來鏈接react和redux的ide

Provider

ReactDOM.render(<Provider store={store}>
    <>
      <Counter></Counter>
    </>
    </Provider>,window.root);
複製代碼

Provider的實現(主要是使用context API)

import React,{Component} from 'react';
    import Context from './context';
    // Provider 主要是提供store使用的
    export default class Provider extends Component{
       render(){
         return (<Context.Provider value={{ store: this.props.store}}>
             {this.props.children}
         </Context.Provider>)
     }
    }
複製代碼

connect

第一次執行傳遞兩個參數mapStateToProps和mapDispatchToProps,兩個都是一個函數分別傳遞state和dispatch參數,返回對象。函數

let mapStateToProps = (state) => { // store.getState()
       return {
        number: state.counter.number,
       }
     };
     let mapDispatchToProps = (dispatch) => { // store.dipspatch
       return {
        add: (n) => dispatch(actions.add(n))
      }
     }
    //若是connect 第一次執行的函數 ,若是第二個參數是對象類型 會自動內部調用bindActionCreator來實現 
    export default connect((state)=>state.counter,actions)(Counter)
複製代碼

connect實現

context API + 高階組件ui

import React from 'react';
    import Context from './context';
    import { bindActionCreators} from 'redux'; 
    let connect = (mapStateToProps, mapDipsatchToProps)=> (Component)=>{
      return ()=>{
        class Proxy extends React.Component{
          state = mapStateToProps(this.props.store.getState());
          componentDidMount(){
            this.unsub = this.props.store.subscribe(()=>{
              this.setState(mapStateToProps(this.props.store.getState()))
            })
          }
          componentWillUnmount(){
            this.unsub();
          }
          render(){
            let mapDispatch;
            if (typeof mapDipsatchToProps === 'object'){ //若是第二個參數傳遞的是一個對象,把對象直接進行包裝便可
              mapDispatch = bindActionCreators(mapDipsatchToProps,this.props.store.dispatch);
            }else{
              mapDispatch = mapDipsatchToProps(this.props.store.dispatch);
            }
            return <Component {...this.state} {...mapDispatch}></Component>
          }
        }
        return <Context.Consumer>
          {({store})=>{
            // 將狀態 和dispatch 拿到執行函數 把結果對象傳遞給本來的component渲染
            return <Proxy store={store}></Proxy>
          }}
        </Context.Consumer>
      }
    }
    export default connect;
複製代碼
相關文章
相關標籤/搜索