在前面的幾小節中已經完成了一個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代碼進行按照特定的職責,功能結構進行拆分的,其實也就是把以前各個邏輯代碼拆分到各個文件當中去單獨管理的 編程
完整的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,這個流程是固定的
固然這個代碼仍然優化的地方,咱們在後續當中,仍會進一步的拆分的