redux、react-redux執行流程簡單解析

其實不想看react-redux、redux的源碼,平時不太喜歡用,尤其是簡單的頁面,然而總是會遇到複雜點的頁面的,所以還是要了解下,搜索了下,講react-redux、redux的文章很多,但是,好像都不太能理解,可能是風格不太一樣,沒辦法還是隻能自己看,看了就記錄下吧。

只講最簡單的使用涉及的東西,目前沒怎麼用中間件什麼的。react-redux版本6.0.1,redux版本4.0.1

使用的例子如下:

main.jsx文件

import ReactDOM from "react-dom";
import React from "react";

import Comp1 from "./comp1";
import {createStore} from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './reducers';

class App extends React.Component {
  render() {
    return (<div>
      <Comp1 />
    </div>);
  }
}

const store = createStore(rootReducer, {
  activeTab: 0,
});

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>, document.getElementById("app"));


=====
comp1.jsx文件

import React, { Component } from "react";
import { connect } from 'react-redux';
import { changeTab } from './actions';

class Comp1 extends Component {
  render() {
    const {activeTab, changeTab} = this.props;
    return (
      <div>
        <p>{activeTab}</p>
        <button onClick={()=>changeTab(33)}>click</button>
      </div>
    );
  }
}

const mapStateToProps = (state, ownProps) => ({
  activeTab: state.activeTab,
});

const mapDispatchToProps = (dispatch, ownProps) => ({
  changeTab: (val) => {
    dispatch(changeTab(val))
  }
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Comp1);

=====
actions.js文件

export const changeTab = (val) => ({
  type: 'change_tab',
  activeTab: val
})

=====
reducers.js文件

export default (state = [], action) => {
  switch (action.type) {
    case 'change_tab':
      return {...state, activeTab: action.activeTab};

    default:
      return state;
  }
};

就是一個main裏面渲染了一個子組件,子組件渲染了一個p標籤和一個按鈕,初始化activeTab等於0,按一下按鈕變成了33。看一下整個過程涉及了哪些東西,首先是redux裏的createStore,然後是react-redux的Provider和connect,沒了,另外都是我們自己寫的東西了。

createStore

先來看一眼createStore幹了啥,打開redux/src/createStore.js看,createStore接收三個參數reducer, preloadedState, enhancer,最後一個不管它,第一個是我們自己寫的reducer,第二個是初始化的時候的state。先翻到createStore函數的最後,看到

dispatch({ type: ActionTypes.INIT })

return {
  dispatch,
  subscribe,
  getState,
  replaceReducer,
  [$$observable]: observable
}

其中getState和replaceReducer比較簡單,不說了,看subscribe這個名字應該能看出來這就是個發佈訂閱,subscribe是註冊監聽事件的函數,裏面有這麼一句nextListeners.push(listener),dispatch是調用reducer,並執行監聽事件的地方,可以在裏面看到

currentState = currentReducer(currentState, action)

...省略一些代碼

const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

看到這裏你會問,是誰調用了subscribe呢?dispatch又是誰調用的呢?不出意外就是react-redux了

Provider

我們打開react-redux/src/components/Provider.js來看,發現Provider是個react組件,看Provider做了什麼

constructor(props) {
    super(props)

    const { store } = props // 這個store就是我們用redux的createStore生成的那個store

    this.state = {
      storeState: store.getState(), // 看一眼
      store
    }
  }

componentDidMount() {
    this._isMounted = true
    this.subscribe() // 看一眼
  }

componentWillUnmount() {
    if (this.unsubscribe) this.unsubscribe() // 看一眼
    this._isMounted = false
  }

componentDidUpdate(prevProps) {
    if (this.props.store !== prevProps.store) {
      if (this.unsubscribe) this.unsubscribe() // 看一眼

      this.subscribe() // 看一眼
    }
  }

...省略一些代碼

render() {
    const Context = this.props.context || ReactReduxContext

    return (
      <Context.Provider value={this.state}>
        {this.props.children}
      </Context.Provider>
    )
  }

構造函數和生命週期一看,基本上知道Provider做了什麼事情了吧,redux的createStore裏的subscribe函數就是Provider調用的,那麼再來看this.subscribe函數幹了啥

subscribe() {
    const { store } = this.props

    this.unsubscribe = store.subscribe(() => { // 調用redux的createStore裏的subscribe函數了
      const newStoreState = store.getState()

      if (!this._isMounted) {
        return
      }

      this.setState(providerState => {
        // If the value is the same, skip the unnecessary state update.
        if (providerState.storeState === newStoreState) {
          return null
        }

        return { storeState: newStoreState }
      })
    })

    // Actions might have been dispatched between render and mount - handle those 看一眼這個註釋
    const postMountStoreState = store.getState()
    if (postMountStoreState !== this.state.storeState) {
      this.setState({ storeState: postMountStoreState })
    }
  }

connect

還剩最後一個connect函數,就是調用dispatch的地方,這個部分怎麼說呢,我還沒看懂哈哈哈,比較複雜,我們的例子裏,mapDispatchToProps的參數dispatch其實就是redux的creatStore裏的那個dispatch,感興趣的同學可以深究,我這裏就不繼續了(逃走),實在不好意思,不過我們的流程已經通了,嗯,很好(?)。

總結

簡單總結一下:redux就是個發佈訂閱,提供了subscribe和dispatch,react-redux在Provider裏進行subscribe,connect的參數mapDispatchToProps裏的dispatch就是redux的dispatch,用react的context API來實現更新機制(這部分上面沒提到,也在connect相關的代碼裏,自己看?)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章