Redux 入坑筆記

Redux 簡要的說就是一個事件分發器和全局state控制檯。react

Redux 有一個全局的state,經過將根組件包進Provider,將store分發給全部的子組件,而子組件經過connect方法,獲取dispatch事件分發函數,以及須要的props(若是有須要也能夠經過connect傳入想分發給子組件的action)npm

定義常量、state和Action

// Reducer/ConstValue.js
export const ADD_NEW = 'add_new';
export const INCREASE = 'increase';
export const DECREASE = 'decrease';
export const DELETE = 'delete';
export INITIAL_STATE = {
    objList: [
        {
            number: 0
        }
    ]
};

// Reducer/ActionCreator.js
import {
    ADD_NEW,
    DELETE
    INCREASE,
    DECREASE
} from './ConstValue';

export function addNew(obj) {
    return {
        type: ADD_NEW,
        obj
    }
}

export function delete(index) {
    return {
        type: DELETE,
        index
    }
}

export function increase(number, index) {
    return {
        type: INCREASE,
        number,
        index
    }
}

export function decrease(number, index) {
    return {
        type: DECREASE,
        number,
        index
    }
}

定義Reducer

Reducer 會註冊給 store,用於處理 action 事件redux

// Reducer/Reducers.js
import {
    ADD_NEW,
    DELETE
    INCREASE,
    DECREASE,
    INITIAL_STATE
} from './ConstValue';

let objList = INITIAL_STATE.objList;

export function objList(state=objList, action) {
    switch (action.type) {
        case ADD_NEW:
            return [...state, action.obj];
        case DELETE:
            return [...state.slice(0, action.index),
                ...state.slice(action.index + 1)
            ];
        case INCREASE:
        case DECREASE:
            return [...state.slice(0, action.index),
                Object.assign({}, state[action.index], {number: number(state[action.index].number, action)}),
                ...state.slice(action.index + 1)
            ];
        default:
            return state;
    }
}

export function number(state=objList[0].number, action) {
    switch (action.type) {
        case INCREASE:
            return state + action.number;
        case DECREASE:
            return state - action.number;
        default:
            return state;
    }
}

IMPORTANT數組

Reducer 傳入(state, action), 經過判斷actiontype, 進行事件分發處理。當事件不少的時候能夠把 Reducer 拆分, 最後經過combineReducers進行組合。架構

每一個 Reducer 都要有明確的返回值,當siwtchdefault的時候則返回傳入的state自己。在處理state的時候,不要在原有參數上修改, 而應該返回一個新的參數, 例如app

return Object.assign({}, state[0], {number: action.number});
// 經過Object.assign獲取一份state[0]的拷貝, 並修改state[0]中的number數據

return [...state, action.obj];
// 經過[...XXX]獲得一個新的數組, 並在最後加入action.obj

combineReducers

// Reducer/index.js
import { combineReducers } from 'redux';

import * as appReducers from './Reducers';

export const AppReducer = combineReducers(appReducers);

上述代碼中, 經過import * as appReducers導出所有的 Reducer, 以後利用combineReducers黑魔法快速的組合 Reducer ide

黑魔法發動條件函數

每一個 Reducer 的名稱, 必須與它獲取的 state 參數名稱同樣, 例如:spa

export function objList(state=objList, action){}

export function number(state=objList[0].number, action){}

若是你任性的不想那麼寫, 那麼就要:code

// Reducer/Reducers.js
export function reducerA(state=objList, action){}
export function reducerB(state=objList[0].number, action){}

// Reducer/index.js
import { combineReducers } from 'redux';
import {
    reducerA
    reducerB,
} from './Reducers';

export function AppReducer(state, action) {
    return {
        objList: reducerA(state.objList, action),
        number: reducerB(state.objList[0].number, action)
    }
}

注入到React

// 安裝React綁定庫
sudo npm install --save react-redux

在根組件上, 經過Provider注入store

只有一個Store

// App/index.js
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import {
  AppReducer
} from '../Reducer/index';
import RootComponent from './RootComponent';

let appStore = createStore(AppReducer);

render(
  <Provider store={appStore}>
    <RootComponent />
  </Provider>,
    document.getElementById('index_body')
);

// App/RootComponent.js
import ContentComponent from './ContentComponent';

class RootComponent extends Component {
    render() {
        return (
            <div>
                <ContentComponent />
            <div>
        )
    }
}

export default ContentComponent;

注入store後, 根組件全部的組件均可以獲取到dispatch函數, 以便進行action的分發處理

子組價獲取props和dispatch

// App/ContentComponent.js
import {
    increase,
    decrease
} from '../Reducer/ActionCreator';

class ContentComponent extends Component {
    render() {
        const {obj, increaseNumber, decreaseNumber}
        return (
            <div>
                <span 
                  onClick={() => {
                      increaseNumber(1);
                  }}>加一</span>
                <span>{obj.number}</span>
                <span
                  onClick={() => {
                      decreaseNumber(1);
                  }}>減一</span>
            </div>
        )
    }
}

// 定義props篩選函數, 以state做爲傳入參數, 選出須要注入該組件做爲props的state. 不是必須, 不寫則state做爲props所有注入
const mapStateToProps = (state) => {
    return {
        obj: state.objList[0]
        // objList: state.objList 
        // 原本想寫list增刪邏輯的可是太懶了暫時擱淺..
    }
}

// 定義action篩選函數, 以dispatch做爲傳入參數, 選出須要注入該組件須要使用的action. 不是必須
const mapDispatchToProps = (dispatch) => {
    return {
        increaseNumber: (number) => {
            dispatch(increase(number));
        },
        decreaseNumber: (number) => {
            dispatch(decrease(number));
        }
    }
}

import { connect } from 'react-redux';
export default connect(mapStateToProps, mapDispatchToProps)(ContentComponent);
// 不使用篩選函數的時候:
// export default connect(mapStateToProps)(ContentComponent);
// export default connect()(ContentComponent);

在經過connect進行注入的時候, dispatch已經做爲組件的 props 而存在了。因此當須要傳入的事件不少, 感受寫mapDispatchToProps很繁瑣的時候, 還有另一種寫法:

// App/ContentComponent.js
import {
    increase,
    decrease
} from '../Reducer/ActionCreator';

class ContentComponent extends Component {
    render() {
        const {obj, dispatch}
        return (
            <div>
                <span 
                  onClick={() => {
                      dispatch(increaseNumber(1));
                  }}>加一</span>
                <span>{obj.number}</span>
                <span
                  onClick={() => {
                      dispatch(decreaseNumber(1));
                  }}>減一</span>
            </div>
        )
    }
}

import { connect } from 'react-redux';
export default connect(mapStateToProps)(ContentComponent);

優劣勢

優點

經過 Redux, 咱們能夠少些不少繁瑣的事件傳輸。在 Redux 以前, 頂層組件處理 state 的改變, 而觸發的事件則有可能須要層層傳遞給底層的子組件, 子組件觸發以後再次層層回調傳到頂層。

但 Redux 的 state 是全局的, 沒必要關心哪一個組件觸發setState()函數, 只須要設定好action和處理 action 的reducer, 由store進行分發處理。

那樣的話, 咱們能夠在底層觸發 state 的改變而沒必要擔憂向上調用 --- 觸發的 action 改變將被 store 監聽, dispatch 給 reducer, reducer經過判斷action.type, 作出適當的反應處理 state

劣勢

  • action 不少很繁瑣

  • 一開始的架構很重要,不然後期改動不易

  • 淡化了傳統React的組件傳輸事件與props的思想, 可能一開始不易理解

相關文章
相關標籤/搜索