React 中的新舊 Context 簡單對比

原文地址:https://github.com/rccoder/blog/issues/30html

媽媽,我不再會濫用 Redux 了前端

前言

context 是各類先後端框架中常常會用到的一個概念,著名 Node 框架 Koa 更是把 context 玩的盡興。React 在很早以前就有 context 的概念,雖然是一個實驗性質的 API,但 react-redux、react -router 等框架類庫卻把它玩了個夠。react

React 中爺爺和孫子,甚至是重孫之間傳遞值或者事件一直是個比較麻煩的事情,隨着 Redux 等狀態管理類庫的出現,你們紛紛開始用這種框架去解決這種隔代傳信息的問題,而且在或大或小的項目中都開始使用。git

一回喜,二回憂,在前端視資源體積爲金子的狀況下 「濫用 Redux」 的狀況愈來愈多。github

React 新版本中的 context 終於要轉正了,而且通過了從新的思考與沉澱,與以前 context 在設計哲學上不同,但解決的倒是同一個問題。這樣,或許數據流真的不是不少的項目或許能夠真的擺脫一下 Redux 等去試試自帶的 Context 了。redux

本文將介紹新老 Context 的一些用法和本身的一些思考。後端

子孫傳值問題

首先看一下最簡單的 爺爺給孫子 傳值的問題:api

class Children extends React.Component {
  render() {
    return (
      <div>{ this.props.text }</div>
      )
    }
}

class Parent extends React.Component {
  render() {
    return (
      <Children text="this.props.text"/>
     )
  }
}

class GrandParent extends React.Component {
  render() {
    return (
      <Parent text="Hi, my baby"/>
    )
  }
}
複製代碼

這幾行代碼中都是手動的讓 text 一輩一輩 的往下傳,若是是傳給重孫的話還須要繼續手動往下傳。架構

利用 Context 就能讓這種信息自動的傳遞,再也不讓 中間輩 去擔任消息傳遞人,作一些沒太大意義的事。composer

老 Context

const PropTypes = require('prop-types');

class Children extends React.Component {
  static contextTypes = {
    text: PropTypes.string
  }
  render() {
    return (
      <div>{ this.context.text }</div>
    )
  }
}

class Parent extends React.Component {
  render() {
    return (
      <Children/>
    )
  }
}

class GrandParent extends React.Component {
  static childContextTypes = {
    text: PropTypes.string,
  }
  getChildContext() {
    return {
      text: 'Hi, my baby'
    }
  }
  render() {
    return (
      <Parent text="Hi, my baby" /> ) } } 複製代碼

GrandParent 上經過 getChildContext 給 context 對象添加了 text 的屬性,這個屬性能夠在 GrandParent 的任何一個子孫(子組件)中訪問。

同時,爲了方便在各類生命週期中使用 context,部分生命週期都給 context 留了接口,具體能夠參考 Referencing Context in Lifecycle Methods

新 Context

老式的 context 和依靠中間輩一層層去傳遞數據相比確實是酷酷的,但總感受不 React。或許這也是爲何以前一直不建議使用的緣由吧。

同時還有一個比較🤢的 context 更新問題,更多能夠參考 How to safely use React context

在 React 16.3 中 新版本的 Context 出爐了,感興趣的能夠參考 rfc提案

新版 context 之下上面的代碼這樣寫:

const AppContext = React.createContext();


class Children extends React.Component {
  render() {
    return (
      <AppContext.Consumer>
        {
          context => {
            return (
              <div>{context.text}</div>
            )
          }
        }
       </AppContext.Consumer>
     )
   }
}

class Parent extends React.Component {
  render() {
    return (
      <Children />
    )
  }
}

class GrandParent extends React.Component {
  render() {
    return (
      <AppContext.Provider
        value={{
          text: 'Hi, my baby'
        }}
       >
         <Parent />
       </AppContext.Provider>
     )
   }
}
複製代碼

新版 Context 用 createContext 去初始化一個 context,返回的對象中有 providerconsumer 方法。provider 是之外層容器的方式去包裹住 context 要做用的最外層組件(使用過 Redux 的同窗對這點應該有種似曾類似的感受),而後須要使用到 context 的時候須要用 consumer 去包裹一下。須要注意的是 consumer 包裹的裏面的寫法,不是普通的組件。

雖然 context 能夠是一個 Object,但仍是避免不了業務邏輯中會出現多個 context 的問題,consumerprovider 一一對應的模式會形成花式嵌套地獄,可使用偉大社區產生的 react-context-composer 對 context 進行 composer,源碼也很是簡單易懂。

Context 會讓 Redux 消失嗎?

不會,解決的終極問題不徹底同樣!

Redux 解決的是大型軟件架構中數據流傳輸的問題;context 解決的是子孫之間方便數據交互的問題。有必定的類似性,但不屬於同等性質。

延伸閱讀

題外

文章內容第一時間更新地址爲:https://github.com/rccoder/blog/issues/30。爲保證看到的是最新的,交流 & 閱讀優先點擊 這裏

相關文章
相關標籤/搜索