redux和react-redux
react的流程:
1. 可以看到,一般都是團長等高階幹部商量好對策之後(this.state設定好)
2. 把命令一層層的傳遞下去執行(this.props渲染)
3. 要是哪裡發生了什麼新的敵情了(想更新頁面內容了)
4 .就得一層層往上報告(通過回撥一層層把資料傳上去),此過程也必須一層層往上傳遞,不能越級,下面有解釋
5. 團長做出決斷後再發布命令傳下去執行(通過setState修改資料並重新渲染)
這個過程是不能越級的,比如說你一連長髮現了敵情就不能直接報告團長,而必須先報告給一營長,一營長再報告給團長,這裡層級還不是特別深,你再來個排長,班長什麼的,按照這種模式,等團長知道敵情,敵人都打到家門口啦,又或者說一連長想找三連長喝個酒,還得先把這個訊息傳給營長,再傳給團長,再傳給二營長再傳給三連長,這……
Redux橫空出世
所以說層級不深,組價之間也沒有什麼公用資料的時候,用React自身的setState其實也可以了,可是巢狀一深,或者元件有一些公用資料時就比較麻煩了,於是就有了redux(其實之前還有個flux),回到這個例子就是,他們在整個團之外又建立了一個通訊班(Redux):
分清兩個state
在說Redux之前,我想說一下自己學的時候遇到的一個小坑,就是Redux中的state和React中的state完全不是一回事,React中的state是元件內部自己的狀態資訊,而Redux中的state是Redux自己的資料,然後React就拿Redux中的資料來用,其實Redux也可以在其他框架下使用,並不是非要跟React一起使用。
簡單畫個圖看起來就像下面這樣:
這裡只是一個很簡單的示意圖,實際使用並非如此,這個圖示為了讓大家理解React中的資料和Redux中的資料是獨立的,並沒有半毛錢關係
Redux
現在讓我們拋開戰鬥編制(React),單看通訊班(Redux)。
其實網上講Redux的教程非常多,這裡就簡單說一下:
store
store:首先要建立一個物件store,這個物件有各種方法,用來讓外界獲取Redux的資料(store.getState),或者讓外界來修改Redux中的資料(store.dispatch)
import { createStore } from'redux'; const store = createStore(reducer);
action
action:描述我要幹啥,一般是一個物件的形式,其中有一個type欄位是必須要有的,比如:{ type:‘請求增援’ },還可以帶點資料{ type:‘請求增援’,gun:"100" }
reducer
reducer:擼開袖子真刀實槍的就去幹了,比如一連長要求增援,增援要求是100杆槍,團長馬上就給你加了100杆槍送了過去。
const defaultState = 0; const reducer = (state = defaultState, action) => { switch (action.type) { case '請求增援': return state + action.gun; default: return state; } };
action和reducer也可以想象成產品經理和程式設計師的關係。
產品經理:“我要一個按鈕,圓角的”
程式設計師:“嗯,做好了”
產品經理:“換個顏色吧,紅色”
程式設計師:“ok,換好了”
差不多就是這樣,產品經理並不操心具體怎麼實現的,他只說他想要幹什麼(type),然後再提點實現的要求(各種其他的資料),程式設計師就去具體實現(reducer,修改state,然後返回一個全新的state,這裡注意我們並沒有直接返回原來的state,我們返回的是一個全新的state物件,因為reducer函式是一個沒有副作用的純函式)
那怎麼去觸發這個操作(action)呢,就好比說我一連長髮現敵情了,我怎麼報告給通訊班,讓通訊班來處理呢?
就是上面提到過的store.dispatch,不過還要加一個引數,那就是action
store.dispatch({ type:‘請求增援’,gun:"100" })
這樣就可以觸發action,執行reducer,得到一個全新的state。
Redux 和 React
到此為止,Redux自己就折騰完了,那麼Redux自己的資料並沒有用,它要把資料交給React用才行,接下來講一講怎麼把資料交給React來用。
上面我們建立了一個物件store,我們要把這個store物件作為props傳給React,那React就可以用了。
這個store只能有一個,也就只能建立一次,也就是說你必須在最頂層處建立一個store物件,然後再一層層的傳遞下去,才能讓所有的元件都能獲得這個store物件,呼叫它的方法。
獲取Redux中的資料
比如說我要在render函式中顯示Redux的資料,那麼我就可以先獲取它的資料:
store.getState()
然後把這個資料當做props渲染到元件中去就行了。
更新Redux中的資料
如果你要修改它的資料,那就在JSX中呼叫
store.dispatch( { type:‘請求增援’,gun:"100" } )
這個函式可以監聽Redux中state的變化,一旦Redux中的state發生了變化,render函式就會被呼叫,頁面就會被重新渲染。
上面這個過程就是手動呼叫的過程,但這樣呼叫有點麻煩,因為要讓所有的子元件都能應用store中的資料,那麼所有的元件就都要把store當做props傳進來,這也太麻煩了。
還是那之前那個例子來說,你一連長髮現了敵情,是不用層層上報了,可以直接報告給通訊班,通訊班再生成新的命令,可問題是,你從下往上打報告是簡單了,可是從上往下發布命令仍然是一層層的傳遞的呀。
就好比說,一連長髮現了敵情,報告上去,通訊班做出決定讓三連長帶人去打,通訊班還是得通過團長--營長--連長這條路去一層層釋出命令,能不能讓通訊班直接就通知三連長呢,當然是有的,這就是我們的React-redux庫
React-redux
這個是需要你自己去用npm額外安裝的。
使用這個方法之後,我們就不需要一層層往下發布命令了
在React-redux中有兩個比較關鍵的概念:Provider和connect方法。
一般我們都將頂層元件包裹在Provider元件之中,這樣的話,所有元件就都可以在react-redux的控制之下了,但是store必須作為引數放到Provider元件中去
<Provider store = {store}> <團長/> <Provider>
這個元件的目的是讓所有元件都能夠訪問到Redux中的資料。
這個比較簡單,我們主要講connect方法。
connect方法:
connect(mapStateToProps, mapDispatchToProps)(MyComponent)
其實connect方法一共有4個引數,這裡主要講前兩個。
mapStateToProps
字面含義是把state對映到props中去,意思就是把Redux中的資料對映到React中的props中去。
也就是說你React想把Redux中的哪些資料拿過來用。
比如這裡二連這個元件想要渲染自己槍支的數量。就可以直接在二連這個元件中把Redux中的gunOfErlian拿過來用
const mapStateToProps = (state) => { return { gun: state.gunOfErlian } }
然後渲染的時候就可以直接使用this.props.gun
class Erlian extends Component { constructor(props){ super(props); } render(){ return( <div>this.props.gun</div> ) } } Erlian = connect()(Erlian); export default Erlian;
那麼這樣就可以實現渲染,就是把Redux中的state變成React中的props。
mapDispatchToProps
通過上面的分析,相信這個函式也很好理解,就是把各種dispatch也變成了props讓你可以直接使用
然後就到了我們這裡最重要的一點了。
const mapDispatchToProps = (dispatch) => { return { onClick: () => { dispatch({ type: '請求增援', gun : 100 }); } }; }
更改一下上面的Erlian元件
class Erlian extends Component { constructor(props){ super(props); } render(){ return( <div>this.props.gun</div> <button onClick = {this.props.onClick}>請求增援</button> ) } } Erlian = connect()(Erlian); export default Erlian;
當我點選請求增援按鈕後,Erlian元件的槍支數量會自動的更新,而不需要我們手動的去用store.subscribe訂閱render函式以達到更新頁面的目的。
這樣一來我們就不需要一層層的傳遞store物件了。
這種隨處都可以使用、修改Redux中的資料的方式確實很方便,但Redux推薦的最佳實踐還是在儘可能少的地方使用connect,把邏輯,資料相關的都放到容器元件中去處理,其他的元件都由容器元件所生成的props一層層傳遞下去然後渲染(傻瓜元件),這裡就不多說了。
這一次的小結差不多就這樣了,許多程式碼細節部分都沒有寫,更多的是對他們的作用的理解,因為自己在學習的時候,更多的是一些理解方面的困惑,而更多更全面的程式碼部分在Redux官方文件或是阮一峰老師的部落格中都已經寫得非常清楚,大家可以去看看,理解了上面許許多多的名詞以及他們的含義之後,相信那些文件會更容易看懂。