原文地址:React's ⚛️ new Context APIjavascript
做者:kentcdoddshtml
這再也不是一個 實驗性的 API
,而且它更符合 工程化
的理念,目前它已成爲 React 一級棒的 API
。前端
⚠️ :你們能夠經過 newsletter 獲取我最新的資訊,我通常每兩週經過郵件發送一次,你們能夠經過本身的收件箱獲取更多的內容。java
React
中的 context API
相信你們都知道吧,可能跟大夥同樣,當看到 React
的官方文檔是這樣時,都不敢直接使用它。react
第一條搜索結果顯示的就是 爲何不建議使用 context,讓你們瞬間產生憂慮,該章節是這麼描述 context
的:git
若是你想讓你的應用更加穩定,就別使用
context
,由於這是一個實驗性的API
,在將來的React
版本中可能會發生改變。github
⚠️ 注意,這裏的改變包括 中斷
,終止
,再也不使用
的含義。redux
你曾經歷過嘗試在一個 層級很深的組件
中獲取 最外層組件
的 state
的痛苦麼,這種痛苦叫 prop drilling
,可謂讓人接近崩潰的。當遇到這種情形時,你確定不會喜歡用 props
來傳遞數據,由於若是中間有個組件發生改變,這個代價將是幾何 :joy:。api
實際上,你能夠經過使用常規的 JavaScript module
來規避以上的問題,將數據存放在某個 module
中,就能夠實如今任何地方 訪問/導入
,但這麼作想要 更新
卻很麻煩(你必須實現一個 event
在數據更新時觸發,通知用戶數據發生改變),而且,服務端渲染
對 module
也會有 影響。微信
所以,像 redux 這樣的負責 狀態管理
的第三方庫進入了你們的視野。它容許你在任何地方從 store
獲取數據,你須要作的只是使用 <Provider />
包裝一下,而後就能夠神奇地在 connected
的組件中輕鬆地獲取想要的數據了。
然而,若是我告訴你 <Provider />
就是在使用 context
這個 實驗性 API
呢?😱 事實上也是這樣的!provider
組件將數據存進 context
中,connect
高階組件從 context
獲取數據,因此,redux
並不容許你的數據能夠在任何地方訪問,context
就是這樣。
因此,爲何還要使用 context
呢?多是你們已經深深地愛上它了吧!即便你沒有直接使用 context
,你的應用程序也會經過引用像 react-redux, MobX-react, react-router, glamorous 這樣的第三方庫間接用到它。
如今清楚了,咱們是如此地熱愛 context
,但官方文檔的警告依然還在:在 React 的將來版本中,可能再也不使用它
,好消息是,context
要正式跟你們打招呼了,你們極有可能比以前更愛它。
一個月前,React 團隊
從 yarn,rust 和 Ember 的 rfcs 倉庫
受到啓發,創建了一個本身的 rfcs 倉庫。倉庫第一個 PR
來自 Andrew Clark(React 團隊核心成員),PR
標題爲 New version of context,其中 Andrew Clark
概述了將來新版本的 context
是怎樣的,以後還存在一些有趣的討論,幾天後,Andrew Clark
就向 React
倉庫提了一個 New context API 的 PR
。
那麼,到底有什麼改變呢?肉眼估計新的 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 prop
的context API
,你可使用context API
輕鬆實現高階組件
或其餘功能。
新的 context API
主要由如下三部分組成
React.createContext
用於傳遞 初始值
(可選擇 使用 bitmask 的一個奇妙的選擇性退出函數),返回一個包含 provider
和 consumer
的對象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 API
(或普通的 render prop pattern
)的問題不少次,就是如何組合 providers
和 consumers
,當在一個 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>
}
}
複製代碼
這裏的目標是使用常見的案例,結合特殊功能的函數/組件,使案例更加 工程化
。
除此以外,你們還能夠參考 jmeas 的 react-composer。
但須要說起的是,在實踐中,我並不建議你們嵌套渲染 props components
,不管何時,均可以選擇建立多個簡單易用的組件,而後組合使用。
正如上面所說的,我對這個 API
充滿了期待。目前暫未發佈,但應該會包含在下一個 minor
版本中。不一樣擔憂,以前的 API
會繼續正常工做,直到下一個 major
版本發佈,因此,每一個人都有時間遷移。還有不要忘了,React
團隊在 Facebook
有超過 50,000
個 React components
須要維護,因此,未來頗有可能會發佈一個 codemod
去自動更新大多數人的代碼(就像以往同樣)。
我很高興這個 新 API
可以提供,正如我在 twitter 中說起的。
關注微信公衆號:創宇前端(KnownsecFED),碼上獲取更多優質乾貨!