(译)React ⚛️ 新的 Context API

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

做者:kentcdoddshtml

这再也不是一个 实验性的 API,而且它更符合 工程化 的理念,目前它已成为 React 一级棒的 API前端

⚠️ :你们能够经过 newsletter 获取我最新的资讯,我通常每两周经过邮件发送一次,你们能够经过本身的收件箱获取更多的内容。java

React 中的 context API 相信你们都知道吧,可能跟大伙同样,当看到 React 的官方文档是这样时,都不敢直接使用它。react

第一条搜索结果显示的就是 为何不建议使用 context,让你们瞬间产生忧虑,该章节是这么描述 context 的:git

若是你想让你的应用更加稳定,就别使用 context,由于这是一个实验性的 API,在将来的 React 版本中可能会发生改变。github

⚠️ 注意,这里的改变包括 中断终止再也不使用 的含义。redux

那么,为何还要使用 context 呢

你曾经历过尝试在一个 层级很深的组件 中获取 最外层组件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-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 中说起的。


关注微信公众号:创宇前端(KnownsecFED),码上获取更多优质干货!

相关文章
相关标签/搜索