redux3 - 通過提交函數派發action及 手寫 實現 bindActionCreators 函數

redux源碼參考

dispatch 即可以是提交一個對象的語法, 還可以提交一個函數的寫法

直接通過提交函數派發動作

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { createStore, bindActionCreators } from './redux';

let initData = {
  num: 10,
};

//  type 類型
const ADD = 'ADD';

const CUT = 'CUT';

// 換成函數語法
const addType = () => ({ type: ADD });
const cutType = () => ({ type: CUT });

function reducers(state = initData, action) {
  switch (action.type) {
    case ADD:
      return {
        num: state.num + 1,
      };
    case CUT:
      return {
        num: state.num - 1,
      };
    default:
      return state;
  }
}
let store = createStore(reducers);

const { num } = store.getState();

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      num,
    };
  }
  componentDidMount() {
    this.unSubscribe = store.subscribe(() =>
      this.setState({
        num: store.getState().num,
      }),
    );
  }
  render() {
    return (
      <div>
        <p>{this.state.num}</p>
        {/* 通過提交函數 */}
        <button onClick={() => store.dispatch(addType())}>+</button>
        <button onClick={() => store.dispatch(cutType())}>-</button>
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById('root'));

這樣一來, 使用函數的語法,也是可以的,而且這種寫法,比直接提交更不容易出錯,也可以統一管理type,但是,我又添加了一個減1 的操作,這樣一來,就store.dispatch()寫了兩次,那如果我有很多個這種類似操作,就有點冗餘了,我就想寫成直接調用某個方法,比如這樣的 <button onClick={() => add()}>+</button>,<button onClick={() => cut()}>-</button>, 這樣我就可以不用寫dispatch了,簡化了Api語法

bindActionCreators() 方法

官方文檔用法

import { createStore, bindActionCreators } from 'redux';
let add = () => ({ type: ADD });
let store = createStore();
let addFn = bindActionCreators(add, store.dispatch);
// 調用,可以看到簡化了
<button onClick={() => addFn ()}> + </button>
// 或者更簡單點
<button onClick={addFn}>+</button>

自己實現bindActionCreators() 方法

可以看到, bindActionCreators(action, dispatch) 接收了兩個參數,一個是要派發的 type類型動作, 另一個是把 dispatch 方法傳進去了,最後採用高階函數的形式

function bindActionCreators(actionCreator, dispatch) {
  // return 一個函數供外部調用
  return function () {
    dispatch(actionCreator());
  };
}
// 使用
let store = createStore();
let add = () => ({ type: ADD });
let addFn = bindActionCreators(add, store.dispatch);

這就完事了,用法一模一樣,但是一直這樣寫,有點分散,假如我有多個的話,這 還是寫了不少代碼量,也很麻煩,所以官方還提供了一個傳入對象的寫法

import { createStore, bindActionCreators } from 'redux';
const actions = {
  add: () => ({ type: ADD }),
  cut: () => ({ type: CUT }),
};
let boundAction = bindActionCreators(actions, store.dispatch);
// 調用
<button onClick={boundAction.addFn}>+</button>

實現這種傳入對象的語法

也就是判斷一下,傳入的是個對象,還是個數組

function bindActionCreators(actionCreator, dispatch) {
  if (ationCreator === 'function') {
    return function () {
      dispatch(actionCreator());
    };
  }
  let boundActions = {};
  for (let key in actionCreator) {
    boundActions[key] = function () {
      dispatch(actionCreator[key]());
    };
  }
  return boundActions;
}

或者箭頭函數,這樣簡化寫

function bindActionCreators(actionCreator, dispatch) {
  // 給每個action綁定創建函數
  const bindActionCreator = (actionCreator) => () => dispatch(actionCreator());

  if (typeof actionCreator === 'function') {
    return bindActionCreator(actionCreator);
  }
  let boundActions = {};
  for (let key in actionCreator) {
    boundActions[key] = bindActionCreator(actionCreator[key], dispatch);
  }
  return boundActions;
}

處理派發action傳參

派發動作時, 偶爾可能還需要傳自己的參數,所以bindActionCreators函數 需要處理傳參,在後邊的高階函數中

function bindActionCreators(actionCreator, dispatch) {
  // 給每個action綁定創建函數
   const bindActionCreator = (actionCreator) => (...args) => dispatch(actionCreator(...args));
  // .....略
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章