原文連接:連接描述https://github.com/jimwmg/JiM...react
前言,對於初學者來講,這個demo理解起來相對簡單,只須要create-react-app ,而後 npm install react-redux npm install redux 便可.(react官方文檔和redux官方文檔)git
本文主要理解redux在react中期的做用,以及react-redux如何將react和redux鏈接起來github
Provider connect 源碼解讀npm
createStore源碼redux
Provider connect2 源碼解讀app
一個比較好的案例dom
ReactDOM.render源碼解析ide
1 react函數
經過setState改變state狀態,觸發ReactDOM.render函數,從新刷新UI組件this
import React ,{Component,PropTypes} from 'react' import ReactDOM from 'react-dom' class Toggle extends React.Component { constructor(props) { super(props); this.state = {count: 1}; // This binding is necessary to make `this` work in the callback this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(prevState => ({ count: prevState.count+1 })); } render() { return ( <button onClick={this.handleClick}> {this.state.count} </button> ); } } console.dir(Toggle); ReactDOM.render( <Toggle />, document.getElementById('root') );
2 react-redux
經過給store註冊render函數,每次dispatch的時候,都會觸發render函數(dispatch函數執行的時候,會執行傳入的reducer和綁定的全部的監聽函數 )
import React ,{Component,PropTypes} from 'react' import ReactDOM from 'react-dom' import {createStore} from 'redux' const increaseAction = {type :'INCREASE'} function reducer(state = {count: 0},action){ switch(action.type){ case 'INCREASE' : return {count : state.count+1} default : return state } } const store = createStore(reducer) console.log(store); console.log(store.getState()); //=========================若是沒有這段代碼,視圖將不會更新,可是state狀態確實是改變了的 function render(){ ReactDOM.render( <Toggle />, document.getElementById('root') ); } store.subscribe(render);//註冊監聽事件,dispatch函數會執行註冊的監聽事件;此時的監聽事件的做用就是將試圖的UI更新,而若是沒有觸發ReactDOM.render事件,那麼UI不會更新; //=========================若是沒有這段代碼,視圖將不會更新,可是state狀態確實是改變了的 class Toggle extends React.Component { render() { return ( <button onClick={()=>{store.dispatch(increaseAction);console.log(store.getState().count); }}> {store.getState().count} </button> ); } } console.dir(Toggle); ReactDOM.render( <Toggle />, document.getElementById('root') );
3 react redux react-redux
經過第二部分代碼咱們能夠看出來,redux確實能夠幫助咱們管理代碼,可是有一點很差的地方就是每次state的狀態改變的時候,都須要從新手動刷新視圖.
react-redux 提供兩個函數,一個是Provider,該組件函數定義的時候,大概實現以下:
能夠看出Provider組件可使得子組件獲取到store對象,也就是說能夠獲取到store對象中的state,dispatch,subscribe等;
class Provider extends Component { getChildContext() { return { store : this.props.store }; } render() { return this.props.children; //表示渲染Privider組件的子元素 } } Provider.childContextTypes = { store: React.PropTypes.object }
一個是connect函數 const WrapToggle = connect(mapStateToProps,mapDispatchToProps)(Toggle),高階組件
該函數的做用是經過mapStateToProps和mapDispatchToProps函數,將將一些屬性添加到Toggle組件的props上,同時
當組件第一次加載的時候,給經過Provider組件傳遞下來的store註冊監聽事件,該事件的做用就是執行setState函數,從而實現UI的更新,這也就是connect函數的做用之一,
以上三種state改變,觸發UI的更新的根本仍是經過觸發setState函數執行ReactDOM.render函數;
import React ,{Component,PropTypes} from 'react' import ReactDOM from 'react-dom' import {createStore} from 'redux' import {Provider,connect} from 'react-redux' const increaseAction = {type :'INCREASE'} function reducer(state = {count: 0},action){ switch(action.type){ case 'INCREASE' : return {count : state.count+1} default : return state } } const store = createStore(reducer) console.log(store); console.log(store.getState()); class Toggle extends React.Component { //這個組件通過connect以後,就能夠訪問到經過connect中mapStateToProps,mapDispatchToProps傳遞到此組件的屬性,全部的屬性都會掛載到Toggle組件的props對象上; //此時就能夠在組件中訪問到store整個state狀態樹中某個對應的state[key],以及store對象中的dispatch函數 //將dispatch函數給到相應的DOM事件,即可以觸發分發動做,更新state; //每次更新state以後,都會觸發mapStateToProps,更新對應組件上對應的state,同時,對應組件上 render() { console.log(this.props);//connect函數中stateProps dispatchProps ownProps 三者融合後的結果傳遞給UI組件props對象 //對象的解構賦值 const {value,onIncreaseClick} = this.props return ( <button onClick= {onIncreaseClick}> {value} </button> ); } } const mapStateToProps = (state, ownProps) => { console.log(state); console.log(ownProps); //state就是經過Provider傳遞進來的store.getState()的結果 //ownProps就是connect返回的新組件,這裏是WrapToggle組件上的Props屬性對象 return { value: state.count } } const mapDispatchToProps = (dispatch, ownProps) => { console.log(dispatch); console.log(ownProps); //dispatch就是 經過Provider傳遞進來的store.dispatch函數 //ownProps就是connect返回的新組件,這裏是WrapToggle組件上的Props屬性對象 return { onIncreaseClick: () => { dispatch(increaseAction) } } } const WrapToggle = connect(mapStateToProps,mapDispatchToProps)(Toggle) console.dir(Toggle); console.dir(WrapToggle); //注意 WrapToggle組件添加了一個屬性,方便一會輸出對比,這些屬性就是ownProps對象 ReactDOM.render( <Provider store={store}> <WrapToggle wrapProps='WarpToggleProps'/> </Provider>, document.getElementById('root') );
4 react如何響應store的變化,也就是說什麼時候從新渲染頁面
4.1 單純的react中,經過setState函數,改變state狀態樹,setState函數每次執行都會從新渲染UI視圖
4.2 react搭配redux的時候,經過store連接,react的狀態能夠經過redux來進行管理,此時redux建立的store中存儲了react中的state狀態,此時若是想要更新UI視圖,須要手動綁定事件,此時惟一改變state的函數是dispatch,經過該函數改變state,從createStore源碼中能夠看出來
4.3 react搭配redux的時候, 經過react-redux進行react和redux的鏈接 ;
Provider函數做用:
在connect內部,當state樹發生變化的時候,最終會觸發setState函數,因此會直接觸發UI視圖的從新渲染
4 connect函數參數解析 connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(component)
1)mapStateToProps(state, [ownProps]):函數: 每次state狀態更新的時候都會調用該函數
默認會將dispatch函數添加到component組件中props屬性上.
function mapDispatchToProps(dispatch) { return { todoActions: bindActionCreators(todoActionCreators, dispatch), counterActions: bindActionCreators(counterActionCreators, dispatch) }; } //這裏面mapDispatchToProps函數接受的參數其實就是store.dispatch函數,bindActionCreators函數接受兩個參數,一個是actionCreator,一個是dispatch函數
3)mergeProps(stateProps, dispatchProps, ownProps): 將mapStateToProps() 與 mapDispatchToProps()返回的對象和容器組件自身的props(本案例就是WrapToggle組件的props: wrapProps='WarpToggleProps)合併成新的props並傳入被包裹的組件(Toggle)。默認返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的結果。 這裏也就解釋了爲何Toggle組件中props屬性中有stateProps, dispatchProps, ownProps 這些對象的組合結果了.