React-Redux 原始碼解讀(1)

Zwe1發表於2019-03-29

前言

本片介紹 react-redux 中的 provider api,可以通過學習原始碼瞭解設計哲學,從而提高自身。正所謂,不看看原始碼,怎麼敢說你懂呢??

Provider

Provider 是 react-redux 的核心 api 之一,結合 react context api,用於向元件傳遞狀態集。

使用案例
<Provider store={store}>
  <APP />
</Provider>
複製程式碼

可見 Provider 也是一個常規的 React 元件,我們向這個元件傳入了 store 屬性,它的值即為呼叫 redux 中   creatStore 方法返回的 store。

./Context

import React from "react";

export const ReactReduxContext = React.createContext(null);

export default ReactReduxContext;
複製程式碼

Provider 原始碼

import React, { Component } from "react";
import PropTypes from "prop-types";
// react context, 可以跨元件層級傳遞狀態。
import { ReactReduxContext } from "./Context";

class Provider extends Component {
  // Provider的使用如上例
  constructor(props) {
    super(props);

    const { store } = props;

    this.state = {
      // storeState為redux建立的狀態集合,呈?樹結構的資料物件
      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) {
      // 元件更新時,有可能傳入了新的store。
      // Provider中訂閱了redux的狀態變化。
      if (this.unsubscribe) this.unsubscribe();

      this.subscribe();
    }
  }

  subscribe() {
    // 訂閱props中store的變化。
    const { store } = this.props;
    // 使用redux中的subscibe方法訂閱狀態變化。
    this.unsubscribe = store.subscribe(() => {
      const newStoreState = store.getState();

      if (!this._isMounted) {
        // 對於provider中資料的更新需要保證元件已經掛載結束。
        return;
      }

      this.setState(providerState => {
        // 如果前後兩次狀態未發生變化,則無需進行更新。
        if (providerState.storeState === newStoreState) {
          return null;
        }

        return { storeState: newStoreState };
      });
    });

    // 有可能在reder和掛載兩個時間點之間dispatch action,需要考慮此種情況
    const postMountStoreState = store.getState();
    if (postMountStoreState !== this.state.storeState) {
      this.setState({ storeState: postMountStoreState });
    }
  }

  render() {
    // context可以傳入,預設使用react context
    const Context = this.props.context || ReactReduxContext;
    // provider是整個應用的狀態提供者
    return (
      <Context.Provider value={this.state}>
        {this.props.children}
      </Context.Provider>
    );
  }
}

Provider.propTypes = {
  store: PropTypes.shape({
    subscribe: PropTypes.func.isRequired,
    // disptach在其他api中有用
    dispatch: PropTypes.func.isRequired,
    getState: PropTypes.func.isRequired
  }),
  context: PropTypes.object,
  children: PropTypes.any
};

export default Provider;
複製程式碼

總結

provider api 通過使用 react context 技術,為應用提供通過 redux 生產的狀態集合 store,並在 store 發生更新時,及時更新內部狀態。

注意: context api 需要 react 特定版本的支援。⚠️

相關文章