React進階(4)-拆分Redux-將store,Reducer,action,actionTypes獨立管理

前言

在前面的幾小節中已經完成了一個todolist的添加,刪除的操做,經過把組件的數據放到了Redux中的公共存儲區域store中去存儲,在Redux中進行狀態數據的更新修改css

改變store的數據惟一辦法就是派發action,調用store.dispatch方法,也知道經過getState方法獲取store中的全部狀態數據,而實現組件頁面的更新與store保持同步,必須得觸發註冊subscribe方法,通時還得監聽一個事件處理函數html

用於從新在一次獲取store的數據使頁面同步更新react

在上幾回編寫Redux的代碼中,建立store,reducer,acton,以及actionTypes(動做類型)都是放在一個文件當中進行編寫的,然而更改store可能有多個action動做,全部代碼雜糅在一塊兒,後期維護起來顯然是很是痛苦的git

因此有必要進行將Redux代碼進行按照特定的職責,功能結構進行拆分的,其實也就是把以前各個邏輯代碼拆分到各個文件當中去單獨管理的 編程

Redux(4)-拆分Redux.jpg

完整的TodoList代碼

這是上一節完整的一todolist的代碼,建立store,reducer,以及action,UI組件等都是混寫在一個文件當中的,這樣雖然沒有什麼問題,可是維護起來,很是痛苦,若是一個文件裏代碼行數超過了130行,就應該考慮拆分代碼了的,固然這並非硬性的規定,適當的拆分有利於代碼的維護,可是過分的拆分,也會增長項目的複雜程度json

import React from 'react';
import ReactDOM from 'react-dom';
import { Input, Button, List, message, Modal } from 'antd'; // 引入antd組件庫
import 'antd/dist/antd.css'; // 引入antd樣式


// 1. 建立一個store管理倉庫,從redux庫中引入一個createStore函數
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';

// 2. 引入createStore後,store並無建立,須要調用createStore()後纔有store
//const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()); // 建立好reducer後,須要將reducer做爲參數傳到createStore當中去,這樣store才能拿到reducer的state數據
const store = createStore(reducer, composeWithDevTools(applyMiddleware())); // 建立好reducer後,須要將reducer做爲參數傳到createStore當中去,這樣store才能拿到reducer的state數據

// 3. 建立reducer函數,管理組件共享的數據狀態以及一些動做
// reducer是一個純函數,返回一個新的state給store
// 4. 初始化state值,將原先組件內部的狀態的數據,移除到reducer裏面去管理
function reducer(state = {
    inputValue: '',
    list: []
}, action) {
    console.log(state, action);
    if (action.type === 'handle_Input_Change') {
        // 對原有的上一次的state作一次深拷貝,在Redux中,reducer不容許直接修改state
        // const newState = Object.assign({}, state);
        const newState = JSON.parse(JSON.stringify(state));
        newState.inputValue = action.value; // 將新的value值賦值給newState
        return newState;
    }
    if (action.type === 'addInputcontent') {
        const newState = JSON.parse(JSON.stringify(state));
        if (Trim(newState.inputValue) === '') {
            message.error('輸入表單內不能爲空,請輸入內容');
        } else {
            newState.list.push(newState.inputValue); // 往list數組中添加input的內容
            newState.inputValue = '';
            return newState; // 返回newState
        }

    }
    if (action.type === 'deletelist') {
        // 下面這個也是拷貝原對象的一種方式與上面等價
        const newState = Object.assign({}, state);
        newState.list.splice(action.index, 1);
        return newState;
    }
    return state;
}

// 去除先後空格
function Trim(str) {
    return str.replace(/(^\s*)|(\s*$)/g, "");
}
const { confirm } = Modal
// TodoList組件
class TodoList extends React.Component {

    constructor(props) {
        super(props);
        // 5. 在組件內部經過getState()方法就能夠拿到store裏面的數據
        this.state = store.getState();
        // this環境的綁定
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleStoreChange = this.handleStoreChange.bind(this);
        this.handleAddClick = this.handleAddClick.bind(this);
        // 觸發訂閱,讓store感知到state的變化
        store.subscribe(this.handleStoreChange); // 接收一個函數,從新獲取store最新的數據,subscribe裏面必須接收一個函數,不然是會報錯的,這個訂閱函數放在componentWillMount生命週期函數內調用操做也是能夠的
    }
    // componentWillMount(){
    // store.subscribe(this.handleStoreChange); 
    // }
    // 組件卸載,移除時調用該函數,通常取消,清理已註冊的訂閱,定時器的清理,取消網絡請求,在這裏面操做
    componentWillUnmount() {
        store.unsubscribe(this.handleStoreChange);
    }

    render() {
        return (
            <div style={{width:'600px',margin: "100px auto"}}>
                    <div>
                        <Input onChange={this.handleInputChange} value={this.state.inputValue} style={{ width:"300px",marginRight:"10px"}}  placeholder="請輸入內容..." />
                        <Button type="primary" onClick={this.handleAddClick}>提交</Button>
                    </div>
                    <List
                      style={{ width: '300px',marginTop:'10px'}}
                      bordered
                      dataSource={this.state.list}
                      renderItem={(item,index) => <List.Item onClick={this.handleDelList.bind(this, index,item)}>{item}</List.Item>}/>
            </div>
        )
    }

    handleInputChange(e) {
        console.log(e.target.value);
        // 定義action,肯定一個操做,動做,注意action必須遵循必定的規範,是一個對象,type字段是肯定要作的動做,類型,監聽表單輸入框的變化,value是輸入框的值
        const action = {
            type: 'handle_Input_Change',
            value: e.target.value
        }
        store.dispatch(action); // 經過store派發dispatch一個action,只有這裏接收一個action,Reducer裏面才能對新舊數據進行計算等操做

    }

    handleStoreChange() {
        console.log("handleStorechange,觸發了");
        this.setState(store.getState()); // 觸發setState從新獲取store的數據,讓input的數據與store保持同步了的
    }

    // 添加列表的操做
    handleAddClick() {
        console.log("添加按鈕執行了");
        // 定義action動做
        const action = {
            type: 'addInputcontent'
        }
        store.dispatch(action); // 還要將action傳遞給dispatch,這樣store纔會接收到
    }

    // 刪除列表操做
    handleDelList(index,item) {
        this.showDeleteConfirm(index, item);
    }

    showDeleteConfirm(index,item) {
        const action = {
            type: 'deletelist',
            index: index
        }
        confirm({
            title: '肯定要刪除該列表?',
            content: item,
            okText: '確認',
            okType: 'danger',
            cancelText: '取消',
            onOk() {
                console.log('OK');
                 store.dispatch(action);
            },
            onCancel() {
                console.log('Cancel');
            },
        });
    }
}
const container = document.getElementById('root');

ReactDOM.render(<TodoList />, container);
複製代碼

此時,項目的src根目下只有一個index.js文件,項目的目錄樹結構是這樣的redux

D:\公開課\2019\React進階\lesson2
├─split-redux
|      ├─.gitignore
|      ├─package-lock.json
|      ├─package.json
|      ├─README.md
|      ├─yarn-error.log
|      ├─yarn.lock
|      ├─src
|      | ├─index.js
|      ├─public
|      |   ├─favicon.ico
|      |   ├─index.html
|      |   └manifest.json
複製代碼

下面來一步一步拆分的,先從簡單的入手,不斷的簡化代碼的數組

拆分ActionTypes定義成一個常量,獨立管理

改變store裏面state數據,惟一的辦法就是派發action,調用store.dispatch(action)方法bash

而定義action,它得是一個對象,該對象下type類型必須是一個字符串類型值,這個類型值必須和reducer裏面action.type後面的值相同,若是不相等,控制檯雖然不報錯,可是卻會影響實際的功能網絡

代碼以下所示

// 定義action,也就是具體要作的什麼事情
const action = {
      type: 'handle_Input_Change', // 這個type後面的字符串值與在reducer裏面的action.type相同
      value: e.target.value
}
// 字符串類型值要與reducer相同
function reducer(state, action){
    if (action.type === 'handle_Input_Change') { // 這個必需要與上面定義相同
        // 對原有的上一次的state作一次深拷貝,在Redux中,reducer不容許直接修改state
        // const newState = Object.assign({}, state);
        const newState = JSON.parse(JSON.stringify(state));
        newState.inputValue = action.value; // 將新的value值賦值給newState
        return newState;
    }
}
複製代碼

在根目錄src下建立一個store文件夾,而後在新建一個actionsTypes.js

把上面action對象下的type的類型值定義成一個常量,而後對外暴露出去,由於這個動做type類型每每是固定的,通常不怎麼去改變,類型值與常量名都定義成同名,這裏的類型值與常量名設置成同名不必定非要一致,可是這已是你們約定俗成的一種規定,是個良好的開發習慣

定義actionType類型以下所示,將action的type類型值定義成常量

const CHANGE_INPUT_VALUE = 'CHANGE_INPUT_VALUE';

export {
	CHANGE_INPUT_VALUE
}
複製代碼

而後在須要使用actionType類型處,引入該暴露的變量對象便可

import { CHANGE_INPUT_VALUE } from './store/actionTypes'; // 引入actionTypes類型

handleInputChange(e) {
        const action = {
            type: CHANGE_INPUT_VALUE,  // 這裏引入上面定義的變量對象
            value: e.target.value
        }
        store.dispatch(action); // 經過store派發dispatch一個action,只有這裏接收一個action,Reducer裏面才能對新舊數據進行計算等操做

    }

複製代碼

以此類推,按照以上模式把action裏面的type類型值都更改爲常量,放到一個文件(actionTypes.js)去管理的,這個文件只用於定義動做action類型的常量

由於上面的代碼中的action有三個:因此完整的以下所示:

const CHANGE_INPUT_VALUE = 'CHANGE_INPUT_VALUE';  // 監聽input框輸入值的常量
const ADD_INPUT_CONTENT = 'ADD_INPUT_CONTENT';    // 添加列表
const DELETE_LIST = 'DELETE_LIST';                // 刪除列表


export {
	CHANGE_INPUT_VALUE,
	ADD_INPUT_CONTENT,
	DELETE_LIST
}
複製代碼

而後在須要使用action Type的地方引用便可

import { CHANGE_INPUT_VALUE, ADD_INPUT_CONTENT, DELETE_LIST } from './store/actionTypes'; // 引入actionTypes

// 監聽input變化動做
handleInputChange(e) {
        const action = {
            type: CHANGE_INPUT_VALUE,
            value: e.target.value
        }
        store.dispatch(action);

}

// 添加列表的操做
handleAddClick() {
    // 定義action動做
    const action = {
        type: ADD_INPUT_CONTENT
    }
    store.dispatch(action); // 還要將action傳遞給dispatch,這樣store纔會接收到
}

// 刪除列表操做
    handleDelList(index,item) {
        this.showDeleteConfirm(index, item);
    }

    showDeleteConfirm(index,item) {
        const action = {         // action在這裏
            type: DELETE_LIST,   
            index: index
        }
        confirm({
            title: '肯定要刪除該列表?',
            content: item,
            okText: '確認',
            okType: 'danger',
            cancelText: '取消',
            onOk() {
                console.log('OK');
                 store.dispatch(action);
            },
            onCancel() {
                console.log('Cancel');
            },
        });
    }
複製代碼

通過上面的處理,關於action的type類型值就已經拆分出去了的,至於拆分action中type類型值的好處就是,當你由於不當心把actionType拼寫錯誤時,它會有很好的錯誤異常提示,這就是定義成一個常量的好處

拆分action,將它封裝到一個函數裏面去管理

在上面的代碼中,只是把action中的type類型值定義成一個常量而後拆分了出去的,可是仍然發現,代碼並無簡化多少,其實在派發action以前,改變store的數據,對於action的動做(具體要作的事情),是不該該直接定義在咱們的組件裏,在事件處理函數裏面定義action對象不是不能夠

可是這樣代碼的內聚性不高,對於簡易的項目,一些action定義在各個組件內,也沒有什麼,可是一多的話,找起來就是災難了的,不利於後續代碼的維護,若是你可以把相應的action代碼拆分出去,後來的同窗必定會感謝你的,固然隨之而然就是增長了點閱讀代碼的複雜度

若是是高手,那絕對從心裏上是要感謝那種把action拆分到一個文件裏去管理的,至於初學者,那確定以爲特麼複雜的,很是繞以及難以理解的,其實只要把Redux的工做流程圖理清楚了,也就天然爲何要這麼拆分了的

一般來講,咱們把上面的action都放在一個action Creators.js的文件中去管理的,管理這個action文件代碼的名字並非固定的,你想要怎麼定義成管理action的任何一個名字均可以,可是最好是見名知意

具體actionCreators.js代碼以下所示:

import { CHANGE_INPUT_VALUE, ADD_INPUT_CONTENT, DELETE_LIST } from './actionTypes'; // 引入actionTypes

// 將action封裝成一個函數,用於返回type類型和須要的參數
function getInputChangeAction(value){
	return {
		type: CHANGE_INPUT_VALUE,
		value:value
	}
}

// 獲取input框內容,添加列表action函數
function getAddInputContentAction(){
	return {
		type: ADD_INPUT_CONTENT
	}
}

// 獲取刪除列表acton函數
function getDeleteListAction(index){
	return {
		type: DELETE_LIST,
		index:index
	}
}

// 上面的也等價於,在Es6中有簡寫函數的形式,與下面是等價的,在React代碼中這種寫法很常見
/*
const getInputChangeAction = (value) => ({
	type: CHANGE_INPUT_VALUE,
	value
});

const getAddInputContentAction = () => ({ 
	type: ADD_INPUT_CONTENT
})

const getDeleteListAction = index => ({  // 當只有一個參數時,圓括號能夠省略,當返回值有多個時,外面須要用一個大括號包裹起來的
	type: DELETE_LIST,
	index
})

*/
// 將變量對象的函數給暴露出去
export {
	getInputChangeAction,
	getAddInputContentAction,
	getDeleteListAction
}

複製代碼

在組件所須要引入actionCreactors的地方,引入actions,以下所示:

import { getInputChangeAction, getAddInputContentAction, getDeleteListAction} from './store/actionCreators';


// 監聽input操做
 handleInputChange(e) {
        const action = getInputChangeAction(e.target.value);
        store.dispatch(action); 
 }
 
 // 添加操做
 handleAddClick() {
    const action = getAddInputContentAction();
    store.dispatch(action);
 }
 
 // 刪除列表操做
    handleDelList(index,item) {
        this.showDeleteConfirm(index, item);
    }

    showDeleteConfirm(index,item) {
        const action = getDeleteListAction(index);
        confirm({
            title: '肯定要刪除該列表?',
            content: item,
            okText: '確認',
            okType: 'danger',
            cancelText: '取消',
            onOk() {
                console.log('OK');
                 store.dispatch(action);
            },
            onCancel() {
                console.log('Cancel');
            },
        });
    }

複製代碼

通過上面的action的拆分,如今看來咱們的代碼清晰多了,經過actionCreators來建立action,這是一個很是好的編程習慣,固然若是過分的拆分,就不免會讓人以爲項目複雜,在各個文件之間來回切來切去的,若是不清晰他們之間的關係,那麼的確是比較繞,可是不能由於這樣,就不作拆分的

從長遠來看,拆分action是頗有必要的,一是將事件動做的類型定義成常量給分離出去,二是把總體action單獨封裝成一個函數放在一個單獨的文件中進行管理的,它返回對應的類型和必要的參數的

拆分的目的主要是提升代碼的可維護性

建立store單獨管理

在上面的代碼中,已經解決了Redux工做流程中的右半邊部分,也就是作了action的拆分管理,那麼接下來是整理store和reducer以及React Component了

在store文件夾中建立一個index.js的文件

這個index.js主要用於建立store

import { createStore } from "redux";
// 建立store,調用createStore函數
const store = createStore();


複製代碼

建立reducer,更新state數據操做

在store文件夾下建立reducer.js文件,主要用於更新state數據操做,以下代碼所示

import { message } from 'antd';
import { CHANGE_INPUT_VALUE, ADD_INPUT_CONTENT, DELETE_LIST } from './actionTypes';
const defaultStatus = {         // 默認初始值
	inputValue: 'itclanCoder',
	list: ['川川','111', '222']
}
function reducer(state=defaultStatus, action){
    if(action.type === CHANGE_INPUT_VALUE){
    	const newState = JSON.parse(JSON.stringify(state));
    	newState.inputValue = action.value;
    	return newState;
    }

    if(action.type === ADD_INPUT_CONTENT){
    	const newState = JSON.parse(JSON.stringify(state));
        if (Trim(newState.inputValue) === '') {
            message.error('輸入表單內不能爲空,請輸入內容');
        } else {
            newState.list.push(newState.inputValue); // 往list數組中添加input的內容
            newState.inputValue = '';
            return newState; // 返回newState
        }
    }

    if(action.type === DELETE_LIST){
    	const newState =  JSON.parse(JSON.stringify(state));
    	newState.list.splice(action.index, 1);
    	return newState;
    }
	return state;
}


// 去除先後空格
function Trim(str) {
    return str.replace(/(^\s*)|(\s*$)/g, "");
}

export default reducer;
複製代碼

在建立好reducer後,必定把reducer放到createStore()函數當作參數給傳進去,這樣store纔會真正存儲reducer的數據,同時把store給暴露出去,以下store文件夾中index.js的代碼

import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from 'redux-devtools-extension'; // 這個是redux-devtools調試工具
import reducer from './reducer';  // 引入reducer
// 建立store
const store = createStore(reducer, composeWithDevTools(applyMiddleware()));

export default store;   // 導出store
複製代碼

最後在主入口文件index.js中引入store,全局進行使用的,以下代碼所示

import React from 'react';
import ReactDOM from 'react-dom';
import { Input, Button, List, Modal } from 'antd'; // 引入antd組件庫
import 'antd/dist/antd.css'; // 引入antd樣式
import { getInputChangeAction, getAddInputContentAction, getDeleteListAction} from './store/actionCreators';
import store from './store/';  // 引入store


const { confirm } = Modal
// TodoList組件
class TodoList extends React.Component {

    constructor(props) {
        super(props);
        // 5. 在組件內部經過getState()方法就能夠拿到store裏面的數據
        this.state = store.getState();
        // this環境的綁定
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleStoreChange = this.handleStoreChange.bind(this);
        this.handleAddClick = this.handleAddClick.bind(this);
        // 觸發訂閱,讓store感知到state的變化
        store.subscribe(this.handleStoreChange); // 接收一個函數,從新獲取store最新的數據,subscribe裏面必須接收一個函數,不然是會報錯的,這個訂閱函數放在componentWillMount生命週期函數內調用操做也是能夠的
    }
    // componentWillMount(){
    // store.subscribe(this.handleStoreChange); 
    // }
    // 組件卸載,移除時調用該函數,通常取消,清理已註冊的訂閱,定時器的清理,取消網絡請求,在這裏面操做
    componentWillUnmount() {
        store.unsubscribe(this.handleStoreChange);
    }

    render() {
        return (
            <div style={{width:'600px',margin: "100px auto"}}>
                    <div>
                        <Input onChange={this.handleInputChange} value={this.state.inputValue} style={{ width:"300px",marginRight:"10px"}}  placeholder="請輸入內容..." />
                        <Button type="primary" onClick={this.handleAddClick}>提交</Button>
                    </div>
                    <List
                      style={{ width: '300px',marginTop:'10px'}}
                      bordered
                      dataSource={this.state.list}
                      renderItem={(item,index) => <List.Item onClick={this.handleDelList.bind(this, index,item)}>{item}</List.Item>}/>
            </div>
        )
    }

    handleInputChange(e) {
        const action = getInputChangeAction(e.target.value);
        store.dispatch(action); 
    }

    handleStoreChange() {
        console.log("handleStorechange,觸發了");
        this.setState(store.getState()); // 觸發setState從新獲取store的數據,讓input的數據與store保持同步了的
    }

    // 添加列表的操做
    handleAddClick() {
        const action = getAddInputContentAction();
        store.dispatch(action);
    }

    // 刪除列表操做
    handleDelList(index,item) {
        this.showDeleteConfirm(index, item);
    }

    showDeleteConfirm(index,item) {
        const action = getDeleteListAction(index);
        confirm({
            title: '肯定要刪除該列表?',
            content: item,
            okText: '確認',
            okType: 'danger',
            cancelText: '取消',
            onOk() {
                console.log('OK');
                 store.dispatch(action);
            },
            onCancel() {
                console.log('Cancel');
            },
        });
    }
}
const container = document.getElementById('root');

ReactDOM.render(<TodoList />, container);
複製代碼

上面的代碼是渲染一個todolist組件的功能,顯然對於主入口文件,咱們仍但願它是比較乾淨的

咱們繼續將todolist組件單獨的抽離出去的

抽離容器組件

對於todolist就是一個簡單的組件,那麼咱們能夠把它抽離出去單獨定義的,在根目錄src下建立一個views文件夾,這個文件夾能夠放咱們的視圖組件,在裏面建一個TodoList.js的文件的 具體代碼以下所示:

對於下面用類class定義聲明的TodoList組件,稱做爲一個容器組件,之因此這麼叫,是由於在這個組件裏面包含不少業務邏輯,例如:this壞境的綁定,生命週期函數,以及一些事件處理函數等,負責整個業務功能組件的邏輯實現,也有人叫它聰明組件的,這個只是個稱呼而已,沒有褒貶之義 以下代碼所示

import React from 'react';
import { Input, Button, List, Modal } from 'antd'; // 引入antd組件庫
import 'antd/dist/antd.css'; // 引入antd樣式
import { getInputChangeAction, getAddInputContentAction, getDeleteListAction} from '../store/actionCreators';
import store from '../store/index';  // 引入store


const { confirm } = Modal
// TodoList組件
class TodoList extends React.Component {

    constructor(props) {
        super(props);
        // 5. 在組件內部經過getState()方法就能夠拿到store裏面的數據
        this.state = store.getState();
        // this環境的綁定
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleStoreChange = this.handleStoreChange.bind(this);
        this.handleAddClick = this.handleAddClick.bind(this);
        // 觸發訂閱,讓store感知到state的變化
        store.subscribe(this.handleStoreChange); // 接收一個函數,從新獲取store最新的數據,subscribe裏面必須接收一個函數,不然是會報錯的,這個訂閱函數放在componentWillMount生命週期函數內調用操做也是能夠的
    }
    // componentWillMount(){
    // store.subscribe(this.handleStoreChange); 
    // }
    // 組件卸載,移除時調用該函數,通常取消,清理已註冊的訂閱,定時器的清理,取消網絡請求,在這裏面操做
    componentWillUnmount() {
        store.unsubscribe(this.handleStoreChange);
    }

    render() {
        return (
            <div style={{width:'600px',margin: "100px auto"}}>
                    <div>
                        <Input onChange={this.handleInputChange} value={this.state.inputValue} style={{ width:"300px",marginRight:"10px"}}  placeholder="請輸入內容..." />
                        <Button type="primary" onClick={this.handleAddClick}>提交</Button>
                    </div>
                    <List
                      style={{ width: '300px',marginTop:'10px'}}
                      bordered
                      dataSource={this.state.list}
                      renderItem={(item,index) => <List.Item onClick={this.handleDelList.bind(this, index,item)}>{item}</List.Item>}/>
            </div>
        )
    }

    handleInputChange(e) {
        const action = getInputChangeAction(e.target.value);
        store.dispatch(action); 
    }

    handleStoreChange() {
        console.log("handleStorechange,觸發了");
        this.setState(store.getState()); // 觸發setState從新獲取store的數據,讓input的數據與store保持同步了的
    }

    // 添加列表的操做
    handleAddClick() {
        const action = getAddInputContentAction();
        store.dispatch(action);
    }

    // 刪除列表操做
    handleDelList(index,item) {
        this.showDeleteConfirm(index, item);
    }

    showDeleteConfirm(index,item) {
        const action = getDeleteListAction(index);
        confirm({
            title: '肯定要刪除該列表?',
            content: item,
            okText: '確認',
            okType: 'danger',
            cancelText: '取消',
            onOk() {
                console.log('OK');
                 store.dispatch(action);
            },
            onCancel() {
                console.log('Cancel');
            },
        });
    }
}

export default TodoList;

複製代碼

其實沒有作多大的代碼改變,只是把原先的代碼挪到另外一個文件管理了的,那麼如今的項目目錄結構是這樣的

D:\公開課\2019\React進階\lesson2
├─split-redux
|      ├─.gitignore
|      ├─package-lock.json
|      ├─package.json
|      ├─README.md
|      ├─yarn-error.log
|      ├─yarn.lock
|      ├─src
|      |  ├─index.js          // 主入口文件
|      |  ├─views       
|      |  |   └TodoList.js     // 容器組件
|      |  ├─store               // 組件的數據
|      |  |   ├─actionCreators.js     // action建立者
|      |  |   ├─actionTypes.js        // actionType的類型,定義成的常量
|      |  |   ├─index.js                 // 建立的store主文件
|      |  |   └reducer.js                // 建立的reducer       
|      ├─public
|      |   ├─favicon.ico
|      |   ├─index.html
|      |   └manifest.json
複製代碼

從這個目錄樹中,很是清楚了的,由起初在index.js的代碼,把redux中的store,reducer,action逐漸剝離出去單獨管理了的

總結

本小節主要是對上一節代碼的拆分,將Redux中的store,action,以及reducer分離開來,各自獨立的管理,職責分明,若是項目比較簡單,一開始是能夠寫在一塊的,而後一點一旦的拆分出去的

若是不是老司機,一開始一上來就拆分,若是對Redux的工做流程不是很清晰,不免會有所懵逼的,發現,寫着,寫着,找不到頭緒,不知道本身在寫些什麼的

在實際開發當中,至於拆分的順序,不必定按照我這種方式的,合適的流程應當時,先建立store,而後在建立reducer,肯定要作什麼事情,編寫action,拆分action代碼,其中獲取store就用getState方法,而更改store就要經過dispatch派發action,這個流程是固定的

固然這個代碼仍然優化的地方,咱們在後續當中,仍會進一步的拆分的

相關文章
相關標籤/搜索