React ⚛️ 新的 Context API

原文地址:React's ⚛️ new Context APIjavascript

做者:kentcdoddshtml

這再也不是一個 實驗性的 API,而且它更符合 工程化 的理念,目前它已成爲 React 一級棒的 APIjava

⚠️ :你們能夠經過 newsletter 獲取我最新的資訊,我通常每兩週經過郵件發送一次,你們能夠經過本身的收件箱獲取更多的內容。

React 中的 context API 相信你們都知道吧,可能跟大夥同樣,當看到 React 的官方文檔是這樣時,都不敢直接使用它。
圖片描述react

第一條搜索結果顯示的就是 爲何不建議使用 context,讓你們瞬間產生憂慮,該章節是這麼描述 context 的:git

若是你想讓你的應用更加穩定,就別使用 context,由於這是一個實驗性的 API,在將來的 React 版本中可能會發生改變。

⚠️ 注意,這裏的改變包括 中斷終止再也不使用 的含義。github

那麼,爲何還要使用 context 呢

你曾經歷過嘗試在一個 層級很深的組件 中獲取 最外層組件state 的痛苦麼,這種痛苦叫 prop drilling,可謂讓人接近崩潰的。當遇到這種情形時,你確定不會喜歡用 props 來傳遞數據,由於若是中間有個組件發生改變,這個代價將是幾何 redux

實際上,你能夠經過使用常規的 JavaScript module 來規避以上的問題,將數據存放在某個 module 中,就能夠實如今任何地方 訪問/導入,但這麼作想要 更新 卻很麻煩(你必須實現一個 event 在數據更新時觸發,通知用戶數據發生改變),而且,服務端渲染module 也會有 影響api

所以,像 redux 這樣的負責 狀態管理 的第三方庫進入了你們的視野。它容許你在任何地方從 store 獲取數據,你須要作的只是使用 <Provider /> 包裝一下,而後就能夠神奇地在 connected 的組件中輕鬆地獲取想要的數據了。react-router

然而,若是我告訴你 <Provider /> 就是在使用 context 這個 實驗性 API 呢?? 事實上也是這樣的!provider 組件將數據存進 context 中,connect 高階組件從 context 獲取數據,因此,redux 並不容許你的數據能夠在任何地方訪問,context 就是這樣。composer

因此,爲何還要使用 context 呢?多是你們已經深深地愛上它了吧!即便你沒有直接使用 context,你的應用程序也會經過引用像 react-reduxMobX-reactreact-routerglamorous 這樣的第三方庫間接用到它。

Context 重生啦

如今清楚了,咱們是如此地熱愛 context,但官方文檔的警告依然還在:在 React 的將來版本中,可能再也不使用它,好消息是,context 要正式跟你們打招呼了,你們極有可能比以前更愛它。

一個月前,React 團隊yarnrustEmberrfcs 倉庫 受到啓發,創建了一個本身的 rfcs 倉庫。倉庫第一個 PR 來自 Andrew Clark(React 團隊核心成員),PR 標題爲 New version of context,其中 Andrew Clark 概述了將來新版本的 context 是怎樣的,以後還存在一些有趣的討論,幾天後,Andrew Clark 就向 React 倉庫提了一個 New context APIPR

那麼,到底有什麼改變呢?肉眼估計新的 API 與以前的 API 存在百萬級別的差別。這是我作的一個簡單的 示例

const ThemeContext = React.createContext('light')
class ThemeProvider extends React.Component {
  state = {theme: 'light'}
  render() {
    return ThemeContext.provide(this.state.theme, this.props.children)
  }
}

const ThemeConsumer = ({children}) => ThemeContext.consume(children)

class App extends React.Component {
  render() {
    <ThemeProvider>
      <ThemeConsumer>{val => <div>{val}</div>}</ThemeConsumer>
    </ThemeProvider>
  }
}
你可能注意到示例中使用到一個 render prop,但實際上並無任何關於須要使用 render propcontext API,你可使用 context API 輕鬆實現 高階組件 或其餘功能。

新的 context API 主要由如下三部分組成

  • React.createContext 用於傳遞 初始值(可選擇 使用 bitmask 的一個奇妙的選擇性退出函數),返回一個包含 providerconsumer 的對象
  • provide 函數使用 higher,並能夠接收任何值
  • consume 函數在 provider 以後任何地方使用,並傳遞一個返回 JSX 的函數(這有點像 render prop 組件,但 consume 不是組件)。

我對這個 API 充滿了期待,React 團隊 也將會移除 context 是實驗性 API 的警告,由於它如今是框架 一級棒的特性。這也意味着你們將再也不那麼擔憂使用 context 來解決應用中 prop-drilling 的問題了,對 Redux 也將再也不那麼依賴,對 React 將更加喜歡。

我最近看到的,大概意思是:

你們不是很願意保持使用提倡的 render 方法,加劇了 prop drilling 問題,因此,最終想經過 redux 來緩解

因此,我認爲若是咱們不過早或武斷地去破壞 render 方法,咱們可能就不會那麼痛苦,即使最終咱們實在沒有辦法避免,咱們也能夠經過核心的 React API 來解決。

Context 實踐

我看到了一個關於 context API(或普通的 render prop pattern)的問題不少次,就是如何組合 providersconsumers,當在一個 render 方法中把一堆 render prop 組件放在一塊兒時,就會像這樣 嵌套

圖片描述

那麼,咱們能夠作點什麼來避免呢?其實,我的以爲沒有那麼糟糕,若是你以爲這樣並很差,那麼可使用常規的方法來解決它:utility 函數/組件,下面是一個示例:

const ThemeContext = React.createContext('light')
class ThemeProvider extends React.Component {/* code */}
const ThemeConsumer = ({children}) => ThemeContext.consume(children)
const LanguageContext = React.createContext('en')
class LanguageProvider extends React.Component {/* code */}
const LanguageConsumer = ({children}) => LanguageContext.consume(children)

function AppProviders({children}) {
  return (
    <LanguageProvider>
      <ThemeProvider>
        {children}
      </ThemeProvider>
    </LanguageProvider>
  )
}

function ThemeAndLanguageConsumer({children}) {
  return (
    <LanguageConsumer>
      {language => (
        <ThemeConsumer>
          {theme => children({language, theme})}
        </ThemeConsumer>
      )}
    </LanguageConsumer>
  )
}

class App extends React.Component {
  render() {
    <AppProviders>
      <ThemeAndLanguageConsumer>
        {({theme, language}) => <div>{theme} and {language}</div>}
      </ThemeAndLanguageConsumer>
    </AppProviders>
  }
}

這裏的目標是使用常見的案例,結合特殊功能的函數/組件,使案例更加 工程化

除此以外,你們還能夠參考 jmeasreact-composer

但須要說起的是,在實踐中,我並不建議你們嵌套渲染 props components,不管何時,均可以選擇建立多個簡單易用的組件,而後組合使用。

總結

正如上面所說的,我對這個 API 充滿了期待。目前暫未發佈,但應該會包含在下一個 minor 版本中。不一樣擔憂,以前的 API 會繼續正常工做,直到下一個 major 版本發佈,因此,每一個人都有時間遷移。還有不要忘了,React 團隊在 Facebook 有超過 50,000React components 須要維護,因此,未來頗有可能會發佈一個 codemod 去自動更新大多數人的代碼(就像以往同樣)。

我很高興這個 新 API 可以提供,正如我在 twitter 中說起的。

圖片描述

相關文章
相關標籤/搜索