從react到react-redux到react-redux-react-redux

原文連接:連接描述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源碼中能夠看出來

  • 先執行reducer,改變state狀態
  • 而後會執行經過subscribe註冊的全部的監聽事件,因此若是註冊了setState函數,則能夠實現dispatch執行之後UI更新

4.3 react搭配redux的時候, 經過react-redux進行react和redux的鏈接 ;

  • Provider函數做用:

    • 1)在原應用組件上包裹一層,使原來整個應用成爲Provider的子組件,而Provider組件定義的時候,render函數返回的是子組件,因此渲染的仍是子組件
    • 2) 接收Redux的store做爲props,經過context對象傳遞給子孫組件上的connect
  • 在connect內部,當state樹發生變化的時候,最終會觸發setState函數,因此會直接觸發UI視圖的從新渲染

    • 1)將store對象上的整個state狀態樹上的某個屬性傳遞給被包裹的組件,這裏組件是Toggle,傳遞的屬性是value
    • 2)將store對象上的觸發dispatch函數的onIncreaseClick傳遞給被包裹組件,這裏是Toggle,傳遞的屬性是onIncreaseClick
    • 3)connect函數會將這些屬性一塊兒合併到Toggle組件的屬性props上
  1. 4 connect函數參數解析 connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(component)
    1)mapStateToProps(state, [ownProps]):函數: 每次state狀態更新的時候都會調用該函數

    • 該函數在每次store中的state狀態樹更新的時候都會調用該函數,經過本案例點擊按鈕看到控制檯輸出能夠深化理解
    • 該函數返回的對象必須是plain object
    • 默認爲空,不會將state狀態添加到component組件中
      function mapStateToProps(state) {
      return { todos: state.todos };
      }
      2)mapDispatchToProps(dispatch, [ownProps]):函數:

默認會將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 這些對象的組合結果了.

相關文章
相關標籤/搜索