項目地址 :https://github.com/ZengTianSh...css
Redux是什麼呢?一個狀態管理工具。那是幹嗎用的呢?都知道,React能夠進行單頁應用的開發,能夠對頁面
中各個模塊進行分割造成組件,而組件之間就避免不了事件的傳遞或數據的交互,那Redux就是用來對這些組件
的狀態進行管理的。就比如買家和賣家,快遞是交給第三方(Redux)去完成。react
也行你會說,React不是有本身的一套數據傳遞和事件管理機制麼,何須要引入第三方來插一腳,那麼麻煩呢。
這裏有一些場景來講明引用 React 是否必要:git
用戶的使用方式很是簡單 用戶之間沒有協做 不須要與服務器大量交互,也沒有使用 WebSocket 視圖層(View)只從單一來源獲取數據
用戶的使用方式複雜 不一樣身份的用戶有不一樣的使用方式(好比普通用戶和管理員) 多個用戶之間能夠協做 與服務器大量交互,或者使用了WebSocket View要從多個來源獲取數據
固然啦,本篇章講述的例子是不須要用到 Redux 這一套狀態管理工具的,但爲了講解就須要簡單的例子來講明github
用一個簡單的例子來深刻淺出的理解 Redux的設計思想:
一個簡單的加減器,點擊加號加一,點擊減號減一npm
看圖感受有點亂,梳理一下就清楚了,首先對以上圖幾個名詞作個解釋,它們分別是幹嗎用的,有什麼功能redux
Store 能夠當作是一個容器,整個應用只能有一個 Store ,就比如整個應用只能指定京東快遞公司來運貨。服務器
import {createStore, combineReducers, applyMiddleware} from 'redux'; const store = createStore(reducer);
State :一狀態下的數據,一時間點下的數據。Store對象包含全部數據,想要獲得某個時間點的數據,就要
對Store生成快照,獲得一個數據集合,就叫作state。 store.getState()
能夠獲得state。
Redux規定一個State對應一個View,反之亦然。 就比如一個快遞物件只能給對應的主人,不能給其餘人。app
import {createStore, combineReducers, applyMiddleware} from 'redux'; const store = createStore(reducer); store.getState()
買家要買東西怎麼辦,固然要先下單啦。用戶只能操做 View(好比對view進行點擊),用戶是接觸不到State的,
那State的變化對應View的變化,這就須要View經過一個Action對象來通知State的變化。就比如經過一個
快遞下單(發送一個Action),纔有接下去的物流等一系列操做不是嗎。
Action是一個自定義對象,其中type
屬性是必現的less
cost action = { type:'btnClick', msg:'信息字符串,不是必現' }
store.dispatch() 是view發出Action的惟一方法,store.dispatch()接受一個Action對象,將他發出去。
如今還沒發貨,只是把訂單信息給京東快遞而已,京東是自營企業,有本身的物流倉庫和物流中心,搜到訂單信息
再根據訂單來發貨。dom
store.dispatch(action);
Store 收到一個Action後,必須給出一個新的State,這樣view纔會發生變化,而新的State的計算過程就是
Reducer來完成的。
就想收到一個訂單(Action)後,須要根據訂單來選取貨物,進行包裝。
Reducer是一個自定義函數,它接受Action和當前的State做爲參賽,返回一個新的State
const reducer = (state=defaultState,action) =>{ switch (action.type) { case 'btnClick': return state + action.msg +'更新'; case '其餘type': return state + ‘其餘action.msg’; /* 可添加更多的 case type 來匹配不一樣的Action */ default: return state; } }
接下來 咱們把這套處理訂單的規則(Reducer)給快遞公司(Store),之後有訂單隻須要根據這套規則來發貨就好了
import { createStore } from 'redux'; // store.dispatch 方法會觸發 Reducer 的自動執行 const store = createStore(reducer);
也許你會疑問那須要發送不一樣的 Action怎麼辦 ,沒錯就是增長訂單規則就能夠了,往 Reducer 裏面增長 case ’type’的規則
當 State一旦發生變化,那麼 store.subscribe() 就會監聽到自動執行。 比如收到了快遞(秒送,哈哈)
那收到快遞能幹嗎呢,每錯,就是在這裏從新渲染 View 更新View咯。
let unsubscribe = store.subscribe(() => console.log(store.getState()) render(){ 更新view !!! } ); // 也能夠取消訂閱(監聽) unsubscribe();
下面講解 Redux 在 React下的應用 -- React-Redux
若是使用第一節講述的 Redux 的那一套狀態管理方法來對 React進行數據管理,也是能夠的,但就有些麻煩。
好比我們要在最後本身定義更新View
store.subscribe(() => console.log(store.getState()) render(){ // React 的 render()方法 更新view !!! } );
爲了使用方便,Redux的做者封裝了一個React專用的庫 React-Redux
React-Redux 將組件分爲兩大類,UI組件和容器組件。UI組件只負責UI的呈現,而容器組件用來管理數據和事件。
那怎麼把交互和UI聯繫起來呢,那就使用 React-Redux 提供的 connect 方法。
React-Redux 提供的 connect 方法。就是將 UI組件個容器組件聯繫起來,那規則是什麼呢?
須要有:
輸入邏輯:外部數據(state對象)轉爲 UI組件的參數 輸出邏輯:用戶發出的動車 (Action對象)從UI組件傳遞出去
所以,connect方法的API是這樣的:
import { connect } from 'react-redux' const Comp = connect( mapStateToProps, mapDispatchToProps )(UI)
connect方法接受兩個參數:mapStateToProps 和 mapDispatchToProps ,前者負責輸入邏輯,將state映射到
UI組件的參數 props ,後者負責輸出邏輯,將用戶對UI的操做映射成Action。
mapStateToProps是一個函數,創建一個 state對象到UI組件的props對象的映射關係!
是映射到UI組件的props
對象上(關鍵點,多提醒一下,下面會作解釋)。
const mapStateToProps = (state) => { return { count: state.count } };
mapStateToProps 接受參數state,state的字段(state.count)賦值給 count 屬性,而count屬性是UI組件的
同名參數。
mapStateToProps會定義 Store,每當 state更新就會自動執行這個方法,那自動執行這個方法怎麼就會更新UI呢,
UI更新一個來自自身的 this.state
變化,還有一個來自 this.props
變化都會觸發React組件從新render(),
而 就上面例子 mapStateToProps 接受 state 的變化從而返回一個 賦值 count屬性,而這個屬性是對應UI組件的
props對象的映射,props變化天然會帶動UI組件的更新。
mapDispatchToProps 是 connect的第二個參數,也是一個函數(還能夠是一個對象)。mapDispatchToProps做爲函數,
應該返回一個對象,該對象的每一個鍵值對都是一個映射,定義了 UI 組件的參數怎樣發出 Action。又是一個映射到UI組件的
props參數上!!!
const mapDispatchToProps = (dispatch, ownProps) => { return { increase: (...args) => dispatch(actions.increase(...args)), decrease: (...args) => dispatch(actions.decrease(...args)) } };
上面 mapDispatchToProps函數接受兩個參數,返回一個對象,注意返回對象的屬性是對應UI組件的props參數的。
也就是UI組件怎麼派發一個Action呢,那就是 UI組件調用 props.increase
就會執行 dispatch(Action)
操做,從而派發一個Action。
上面屢次提到 屬性映射到props組件上,子組件在經過props拿到數據或方法進行操做,那props對應的組件是誰呢,
也就是子組件的父組件是誰呢。
React-Redux 就提供了<Provider> 組件 來充當全部UI組件的容器組件,全部UI組件均可以利用props屬性想
<Provider> 組件拿數據。而<Provider> 組件的數據由 store提供。
render( <Provider store={store}> <Index></Index> </Provider>, document.body.appendChild(document.createElement('div')) );
由下圖能夠看出 React-Redux 的大體工做原理,能夠看出UI組件確實只負責UI部分,只經過props參數拿數據和對外
派發數據,而沒有多作業務上的邏輯。而業務邏輯和數據呈現交給了容器組件,UI組件和容器組件是經過 connect()
方法連接的,內部是經過 mapStateToProps 和mapDispatchToProps進行數據傳遞的。整個應用的數據都會通過
Store這個中央處理器的處理。因此不一樣UI組件之間的數據交互能夠把數據都丟給Store這個中央處理器處理,Store
再把處理好的數據回傳給各個UI組件就能夠了
### 3、小例子:加減器
用一段代碼來鞏固前面所學習的知識。實踐強化嘛!哈哈
Main.jsx:
import React, {Component, PropTypes} from 'react'; import {connect} from 'react-redux'; /** * 定義一個 Main組件 */ class Main extends Component{ constructor(){ super(); this.pClick =() =>{ console.log('sssssssss'); }; this.state = { num:0, age:666 } } render(){ // 拿到 this.props 參數 const {count, increase, decrease} = this.props; return( <div> <p className="lesson-2">React lesson-2</p> <p> --------------------------------- </p> <div className="count"> <div>計數:{this.props.count}次</div> <span className="btn" onClick={increase}>+</span> <span className="btn" onClick={decrease}>-</span> </div> </div> ) } } /** * 用來給 組件傳遞數據 * @param state */ const mapStateToProps = (state) => { return { count: state.count } }; /** *用來組件給 容器組件派發數據 * @param dispatch 派發 Action * @param ownProps 組件自身的 props參數 */ const mapDispatchToProps = (dispatch, ownProps) => { return { increase: (...args) => dispatch(actions.increase(...args)), decrease: (...args) => dispatch(actions.decrease(...args)) } }; /** * actions */ const actions ={ increase:() => { return {type: 'INCREASE'} }, decrease: () => { return {type: 'DECREASE'} } }; /** * 鏈接 UI組件 和 容器組件 * @param mapStateToProps 輸入邏輯 * @param mapDispatchToProps 輸出邏輯 */ const Comp = connect(mapStateToProps, mapDispatchToProps)(Main); /** * 輸出一個容器組件 */ export default Comp;
App.js
import React,{Component,PropTypes} from 'react'; import ReactDOM, {render} from 'react-dom'; import {Provider,connect} from 'react-redux'; import {createStore, combineReducers, applyMiddleware} from 'redux'; import Index from './Component/Main.jsx'; import './Style/comm.scss' const store = createStore(reducer); //監聽state變化 store.subscribe(() => { //console.log(store.getState()) }); const reducer = (state = {count: 0}, action) => { switch (action.type){ case 'INCREASE': return {count: state.count + 1}; case 'DECREASE': return {count: state.count - 1}; default: return state; } } render( <Provider store={store}> <Index></Index> </Provider>, document.body.appendChild(document.createElement('div')) );
你也能夠 clone本項目運行調試
clone git@github.com:ZengTianShengZ/react-lesson.git cd lesson-2 npm install npm run hot
以上是對 Redux 的學習和體會,不少資料來源於網上和大神的博客,若有疑問的話能夠 issue,
以爲有幫助的話能夠 star
一下本項目哦 ^-^