我在理解這個流程圖的時候,採用的是一種容易記住的辦法,而且貼切實際工做職責。
咱們能夠把整個Redux工做流程理解成一個圖書館中借書操做。css
所以當咱們理解了每一個部位的身份後,咱們就按照着上面工做流程圖一塊兒來屢一下整個過程。首先借書的人(React Component)發起一個借書的實際操做(Action Creators)傳達(dispatch)一個(action)給圖書館管理員(Store),圖書館管理員須要查閱借書小本本(Reducer),查閱完之後圖書館就能從借書小本本中獲取到返回(return)的信息,再告訴借書的人「OK,我在借書小本本我登記好了,書你能夠拿走了」,這樣借書的人(React Component)就拿走書了。react
是否是如今有點印象對於整個工做流程?chrome
(說了這麼多,不練下怎麼知道爽不爽呢?)
npm
咱們要實現的功能很簡單,就是經過redux去管理數據,數據[1, 2, 3]這時候都是從reducer中取出來的。
redux
主要展現兩個分別爲index.js和todoList.js數組
import React from 'react'; import ReactDOM from 'react-dom'; import TodoList from './TodoList'; ReactDOM.render(<TodoList />, document.getElementById('root'));
話很少說!瀏覽器
import React, { Component } from 'react'; import 'antd/dist/antd.css'; import { Input, Button, List } from 'antd'; import store from './store'; // 等價於 import store from './store/index.js' import { getInputChangeAction, getAddItemAction, getDeleteitemAction } from './store/actionCreator'; class TodoList extends Component { constructor(props) { super(props); this.state = store.getState(); this.handleInputChange = this.handleInputChange.bind(this); this.handleStoreChange = this.handleStoreChange.bind(this); this.handleBtnClick = this.handleBtnClick.bind(this); store.subscribe(this.handleStoreChange); //store中的數據只要被改變,就會自動觸發裏面的動做 } render() { return ( <div style={{marginTop: '10px', marginleft: '10px'}}> <div> <Input value={this.state.inputValue} placeholder='todo info' style={{width: '500px', marginRight: "10px"} } onChange={this.handleInputChange} > </Input> <Button type="primary" onClick={this.handleBtnClick}>提交</Button> </div> <List style={{marginTop: '10px', width: '500px'}} bordered dataSource={ this.state.list } renderItem={ (item, index) => (<List.Item onClick={this.handleItemDelete.bind(this, index)}> {item} </List.Item>) } > </List> </div> ) } handleInputChange(e) { /* 原代碼,現將action封裝到一個獨立的actionCreator.js中 便於維護 const action = { type: CHANGE_INPUT_VALUE, value: e.target.value } */ const action = getInputChangeAction(e.target.value); store.dispatch(action) } handleStoreChange() { this.setState(store.getState()); } handleBtnClick() { const action = getAddItemAction(); store.dispatch(action); } handleItemDelete(index) { const action = getDeleteitemAction(index); store.dispatch(action); } } export default TodoList;
簡單說兩句上述代碼。
1).渲染一個輸入框一個按鈕,點擊按鈕,將輸入框中的數據發送store中並更改list的值,而後組件會接收到store數據變動將新數據渲染。
2).點擊列表中的每一項會刪除該項。其實就是組件發送一個action給store,告訴它,刪掉我點的!
antd
npm install redux --save--dev
store文件總共有四個文件分別以下
dom
// index.js import { createStore } from 'redux'; import reducer from './reducer'; const store = createStore( reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() ); export default store;
簡單解釋兩句以上代碼,從redux中引入一個createStore方法,經過這個方法傳入咱們的小本本reducer,建立一個store。那麼問題來了,第二個參數這麼一長條是啥玩意?莫慌兄dei~咱們爲了更好的管理數據經過使用redux去管理,那麼chrome有一個Redux Devtools插件能夠可視化redux數據。而這一長條就是爲了告訴瀏覽器,據說你有redux可視化數據的插件?還不快給老子顯示一下redux數據!
異步
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './actionTypes'; export const getInputChangeAction = (value) => ({ type: CHANGE_INPUT_VALUE, value }); export const getAddItemAction = () => ({ type: ADD_TODO_ITEM }); export const getDeleteitemAction = (index) => ({ type: DELETE_TODO_ITEM, index });
1).簡單說兩句上面的代碼,就是導出了三個得到action的方法,由於咱們用redux去管理數據的一個目的就是,咱們不在把業務邏輯放在React Component中,而是全封裝在一個actionCreator中。而後咱們就能夠在React Componet中直接引入actionCreator,而後吊用其中暴露的接口便可得到一個action,而後再把這個action派發給reducer。
2).那麼再說兩句action,在redux中action是一個對象,這個對象中有一個參數是type,記錄的就是一個咱們須要怎樣的操做(換句話說就是這是一個怎樣的action),當咱們記錄了這個type的時候,咱們就能夠在reducer小本本中根據咱們所須要的type從而如何去改變store中的數據;其action這個對象中別的參數能夠是咱們作這個操做時須要的別的value。
// actionTypes.js export const CHANGE_INPUT_VALUE = 'change_input_value'; export const ADD_TODO_ITEM = 'add_todo_item'; export const DELETE_TODO_ITEM = 'delete_todo_item';
簡單說兩句上述代碼,這個文件實際上是對action中的type進行封裝成一個常量。這樣作的目的是:若是是一個普通字符串,當咱們在一個項目中屢次拼寫的時候極可能會一個字符沒拼對而出bug,而這個bug咱們還有可能花一天的時間去找,最後你可能會
有童鞋可能會說,我都複製還不行嗎!行!累不累?可是,既然要用redux去管理數據,咱們就一勞永逸吧!
  //reducer.js import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './actionTypes'; const defaultState = { inputValue: '123', list: [1, 2, 3] }; export default (state = defaultState, action) => { // 更改input輸入框的值 if (action.type === CHANGE_INPUT_VALUE) { const newState = JSON.parse(JSON.stringify(state)); //深拷貝 newState.inputValue = action.value; return newState; } // 將input提交的值插入到數組list中 if (action.type === ADD_TODO_ITEM) { const newState = JSON.parse(JSON.stringify(state)); newState.list.push(newState.inputValue); newState.inputValue = ''; console.log(newState); return newState; } //刪除item if (action.type === DELETE_TODO_ITEM) { const newState = JSON.parse(JSON.stringify(state)); newState.list.splice(action.index, 1); return newState; } return state; }
老規矩,講代碼!
1.一般咱們定義倉庫的一個默認值defaultState。
2.咱們導出一個方法。這個方法作的事情就是先記錄不一樣的action.type執行不一樣的操做,返回給store對應操做後的數據。
總結:
當React Component須要執行一個操做時,就會調用actionCreator暴露的接口得到一個action,而後將這個action去dispatch給store,store拿到這樣一個action就會去查小本本,而後根據小本本預先設定好的操做執行並返回對應的結果給store,而後store中的數據就會改變。咱們一般在React Component的constructor初始化時,執行store.subscribe(this.handleStoreChange)。表示的是,當store數據變化時,就會觸發裏面的操做拿到最新的數據。
後續會繼續更新
1.redux-thunk,這個插件使得action除了對象外還能夠是一個函數,這樣咱們能夠將一個異步請求,從react組件中封裝到store中的actionCreator進行管理。
2.redux-immutable ,這個插件使得store中的數據成爲一個immutable不可變對象
3.react-redux,鏈接父子組件的store,使得父組件中引入了store後,如何在子組件中鏈接並使用這個store
----------------做者的話:若是你看到了這裏,那說明你真的是一個棒棒噠,第一次發博,碼文碼字還不是特別專業,不過會慢慢進步的,若有不對的地方,還請你們指點一下!--------------