對不起本文確實有標題黨的嫌疑:) 想要理解本文仍是要先會用react和es6,若是連react和es6都不知道是什麼的話我也沒轍:( html
若是你選擇用react來開發應用,而且你沒對各個組件的狀態進行應有的管理,那麼當應用變得龐大的時候你會發現組件之間的通訊變得錯綜複雜,各個組件之間的數據傳遞每每會亂成一團,從而致使加班、延期、炒魷魚等很差的事情:( 這個時候就須要引入「狀態管理」這個概念來挽救一團亂麻的代碼。狀態管理,就是將各個組件之間相互獨立的狀態和數據給統一的管控起來,讓本來錯綜複雜的數據流向變成單向,這樣狀態就變得容易管理和理解,從而讓程序變得易於維護。react
今天咱們講的就是react目前最流行的狀態管理工具redux和它的一些周邊組件。廢話很少說,咱們先準備好react開發環境,打開ide開始敲代碼。webpack
環境這塊我就不講了,最基礎的webpack+react便可。git
首先先安裝redux(yarn add redux -S),清空src目錄,新建一個入口js文件(index.js),輸入如下內容:es6
import { createStore } from 'redux' const reducer = function (state, action) { console.log(action.type) return state } const store = createStore(reducer) store.dispatch({type: 'hello'})
而後啓動dev server,打開瀏覽器和控制檯,就能夠看到輸出了「hello」。如今來稍微解釋下這段代碼:github
createStore,從字面上理解,就是建立倉儲,這個倉儲用來存放數據和修改數據的方法。web
dispatch,直譯過來是指派、調度,能夠理解成命令store執行修改數據的操做。傳入一個對象來描述要執行的動做。咱們稱這個對象爲action。ajax
reducer,直譯過來是還原劑,這裏就把它理解成存放數據和修改數據的方法的地方。若是把store比喻成倉庫,那麼reducer就是用來裝載貨物的集裝箱。reducer接受的第一個參數是數據,第二個參數用來描述動做,裏面是dispatch過來的對象和數據,咱們能夠利用type屬性結合switch case語句來進行具體的狀態修改。還有要記得返回state,若是沒有返回state就會報錯。redux
咱們把reducer扔到createStore這個函數裏,就返回了一個store。而後再調一下store裏面的dispatch方法,就執行了一次reducer。這樣一個最簡單的redux管理狀態的流程就跑完了。瀏覽器
在這個例子裏咱們只使用了一個reducer,而一個reducer只有一個state,可是咱們的應用確定不止一個組件,這個時候就須要多個reducer。
爲了將多個reducer組合起來,咱們又要引入一個redux裏的函數,叫combineReducers。
import {combineReducers, createStore} from 'redux' const list = function (state = [], action) { //state=[]表示的是state的初始狀態 console.log(action.type) console.log('list') return state } const counter = function (state = 0, action) { console.log(action.type) console.log('counter') return state } const reducers = combineReducers({ list, counter }) const store = createStore(reducers) store.dispatch({type: 'hello'})
這樣就將多個reducer組合起來了。調用dispatch的時候全部reducer都會被執行。
到了這裏咱們就已經能夠進行一些簡單的本地狀態管理了。可是幾乎全部的應用都有涉及到ajax異步請求,這些代碼要放到哪裏呢?若是放到reducer裏的話因爲reducer要求當即返回state,否則報錯。解決方案是有的,不過有些繁瑣,能夠參考阮一峯老師的教程:
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html
若是沒看懂的話也不要緊,若是你可以在項目中運用redux-saga的話,就能夠很輕鬆的解決異步問題了:)
咱們先認真的把redux-saga官方提供的案例給看一看
https://redux-saga-in-chinese.js.org/docs/introduction/BeginnerTutorial.html
redux-saga的使用很簡單,和以前redux的作法差很少。先定義saga(也稱爲effect。相似reducer,不過能夠調用異步方法,不能修改狀態),而後在頂層(index.js)註冊以前寫好的saga便可。
在saga(effect)中,咱們能夠經過takeEvery來監聽dispatch,經過call來調用異步方法,經過put來觸發reducer,經過select來獲取狀態。要注意的是saga都是Generator函數(帶*號),也只有Generator函數裏才能調用yield。這樣異步問題就差很少解決了。
說了這麼多,總得應用到react裏面去吧。react裏的各個組件想要獲取到store裏的狀態和命令store進行數據修改,若是不安裝其餘包的話就只能在根級組件把store一級一級的傳遞下去,中間有一級沒傳遞store那麼以後的組件就所有沒法使用redux進行狀態管理了,這樣顯然是有待改進的。因此咱們還要再裝一個包:react-redux。
React-redux核心的方法只有兩個:Provider和connect。Provider用來包裹根級組件,並接收store,connect用來將組件的props與store鏈接起來,這樣即便不一層層的傳遞store每一個組件也能夠接收到store。
export default connect((state) => { return {list: state.userList.list} // 將store與組件鏈接起來。connect第一個參數是一個函數,要求返回用來描述props和store的對象。 })(List)
這樣咱們基本上就能把redux給實際的應用起來了,可是還有一個問題值得咱們思考:store調用dispatch後全部的reducer都會被執行,而每一個reducer裏面只能用switch case之類的流程控制語句來指定執行哪一個reducer,若是項目一大,各個方法的命名豈不是很容易混亂?彆着急,這個時候須要本文要談到的最後一個包:dvajs。dvajs將一組數據和相應的修改數據的方法包裝成一個module,組件調用dispatch的時候能夠經過指定type屬性來直接調用相應module的effect或者reducer。dvajs的具體使用除了參考官網的案例之外,還能夠參照這篇博文:http://www.javashuo.com/article/p-aehwfnrz-eu.html。只要你可以從redux->redux-saga->react-redux這個流程學下來,就會發現dvajs幾乎沒有多少新知識點,很快就可以上手。
若是以爲教程裏有地方講的不是很理解的能夠將下面這個案例下載下來看一看,相信不少問題都會獲得答案。
一個在線獲取用戶列表,點擊項目可刪除的例子