它更符合工程化, 不再是实验性的," 现在它是一流的 API! 并且它还使用了 RENDER PROP!
注意: 大家可以通过 newsletter http://kcd.im/news 获取我最新的资讯. 我发送每封电子邮件两周后发布到 我的博客 https://blog.kentcdodds.com . 订阅即可在收件箱中获得更早更多的内容!
你在 react 官网上听说过 context API? 如果你听说过, 你会像许多人那样, 因为看过官网的文档, 而害怕直接使用它么:
该搜索结果第一个显示 "为何不用使用 Context" https://reactjs.org/docs/context.html#why-not-to-use-context . 不会激发对 context API. 的大量信心 . 为了使事情更加受关注, 搜索结果这部分说:
如果你想让你的应用更稳定, 别使用 context. 因为这是一个实验性的 API, 在未来的 React 版本中可能会被更改..
那么你为何要使用 context?
你有没有经历过尝试在 react 状态树中从底部组建向顶部组建获取状态值的痛苦? 这种痛苦称作 "prop drilling" 并且 是让人感到崩溃的. 最终你必须通过不关心数据的组件来传递 props, 以便将这些 props 发送给需要关心这些数据的组件. 并且随着你移到这些组建这些痛苦将被扩大.
实际上你可以使用常规的 JavaScript 模块来避免这些问题. 你可以把这些数据放在一个单独的模块中, 这样你就可以随时随地的导入或者访问相关数据. 但是, 在更新的时候会遇到一些麻烦 (你必须实现一个方法来保证实时更新), 并且服务器端的渲染也可能对单例有 问题 https://stackoverflow.com/a/40974748/971592 .
如此, 这就需要 https://redux.js.org/ 这种状态管理库参与进来的地方了 . redux 允许您轻松地从 store(状态树)中的任何位置获取数据. 你所要做的就是使用这个叫做 <Provider /> 用法, 的东西, 神奇的是你的 store(状态树)可以被任何 "连接" 的组件所访问
如果我告诉你 Redux 用法之 <Provider /> 正在使用 context 的特性, 那该怎么办? 确实是这样! provider 组件将数据放入 context 中, 并且 "连接" 高阶组件将数据从 context 中提取出来. 因此, 实际上, Redux 并不允许您的数据在任何地方访问......context 是就是这样!
那么, 为什么你应该使用 context? 那么, 你可能早已经爱上了它了 ! 即使你不直接使用 context, 但是你的 app 已经通过 react-redux,MobX-react,react-router,glamorous 等来使用它!
Context 的重生
所以我们爱上了 context, 但是要记住官方的警告 " 它又可能在之后的 react 版本中被摒弃掉? 现在 context 正式发布了! 你将会喜欢上它!
在一个月以前, the React 团队从 Yarn https://github.com/yarnpkg/rfcs , Rust https://github.com/rust-lang/rfcs , 和 Ember https://github.com/emberjs/rfcs 的 rfcs 仓库中受到了启发, 创建了一个新的自己的 RFCs 仓库 https://github.com/reactjs/rfcs . 第一个从仓库拉代码的是 Andrew Clark https://twitter.com/acdlite (react 核心团队成员) 它被称为 "新版的 context" https://github.com/reactjs/rfcs/pull/2 . 其中, Andrew 描述了新版的 context 将会是什么样的. 在这仓库里有些很有趣的讨论. 几天后, Andrew 就向 React 仓库提了一个 "New context API" https://github.com/facebook/react/pull/11818 的 PR.
所以呢它看起来怎么样? 肉眼估计新的 API 与之前的 API 存在百万级别的差异. 这是我做的一个简单实用的: 实例 https://cdn.embedly.com/widgets/media.html?src=https://codesandbox.io/embed/n4r0qq898j&url=https://codesandbox.io/s/n4r0qq898j&image=https://codesandbox.io/api/v1/sandboxes/n4r0qq898j/screenshot.png&key=a19fcc184b9711e1b4764040d3dc5c07&type=text/html&schema=codesandbox
这是一个更简单的版本, 所以你不必另外打开代码链接:
- const ThemeContext = React.createContext('light')
- class ThemeProvider extends React.Component {
- state = {theme: 'light'}
- render() {
- return (
- `<ThemeContext.Provider value={this.state.theme}>`
- {this.props.children}
- `</ThemeContext.Provider>`
- )
- }
- }
- class App extends React.Component {
- render() {
- return (
- `<ThemeProvider>`
- `<ThemeContext.Consumer>`
- {val => `<div>`{val}`</div>`}
- `</ThemeContext.Consumer>`
- `</ThemeProvider>`
- )
- }
- }
在我的代码例子中你或许注意到了, 我正在使用 render prop Consumer 组件 (最好!), 如果你不喜欢用这种方式, 您可以使用 context API (这就是为什么它是最好的) 轻松实现更高阶组件或其他内容 最新的 context API 由 3 个主要部分组成:
React.createContext
用于传递初始值(可选择 a fancy opt-out function that uses a bitmask https://twitter.com/acdlite/status/957446433656864768 ). , 返回一个包含 provider 和 consumer 的对象
The Provider 组件在树中内更深层次的值, 并接受一个名为值的 prop(可以是任何东西)..
The Consumer 函数在 provider 之后任何地方使用, 并传递一个返回 JSX 的函数.
我对这个 API 充满了期待. React 团队 也将会移除 context 是实验性 API 的警告, 因为, 它现在是框架 "一级棒的特性" https://twitter.com/acdlite/status/957445801302618112 . 这就意味着开发者不要再担心使用 context 来解决应用中 prop-drilling 的问题了, 对 Redux 也将不再那么依赖, 对 React 将更加喜欢 (或许 James Kyle https://medium.com/@thejameskyle 的 Unstated https://github.com/thejameskyle/unstated 是我们一直所期待的).
我最近 看到的 https://twitter.com/kentcdodds/status/911276059051438082 :
我认为, 如果我们能避免过早和任意打断 render 方法, 那么我们就更少的会感受到这种痛苦. 但是, 即使我们感受到了, 我们也有一个坚实的核心 React API 来帮助我们避免这个问题.
Context 实践
我多次遇见一个关于 context API (或普通的 render prop pattern)的问题, 就是如何组合 providers 和 consumers. 当在一个 render 方法中把一堆 render prop 组件放在一起时, 就会像这样 嵌套 https://twitter.com/acdlite/status/955955121979969537 :
所以我们怎么避免这种情况你? 如果这样很麻烦, 你可以用常规的方法来解决: utility 函数 / 组件. 这有个例子:
- const ThemeContext = React.createContext('light')
- class ThemeProvider extends React.Component {/* code */}
- const ThemeConsumer = ThemeContext.Consumer
- const LanguageContext = React.createContext('en')
- class LanguageProvider extends React.Component {/* code */}
- const LanguageConsumer = LanguageContext.Consumer
- 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() {
- return (
- `<AppProviders>`
- `<ThemeAndLanguageConsumer>`
- {({theme, language}) => `<div>`{theme} and {language}`</div>`}
- `</ThemeAndLanguageConsumer>`
- `</AppProviders>`
- )
- }
- }
在这里的目的是为了使用常见的案例, 结合特殊功能的函数 / 组件, 使案例更加 工程化! 有道理么? 我希望它确实如此 我这有另外一个例子, 在这真实的展示出嵌套有多糟糕以及怎样使用一个 https://medium.com/@jmeas 的一个称为 react-composer utility 方法 来实现它链接 https://codesandbox.io/embed/92pj14134y?referrer=https://medium.com/media/4bcc13014bc56311fdb9440b6e28a050?postId=70c9fe01596b
我应该提到的是, 我不希望你需要在实践中嵌套 render props 组建. 无论何时, 你都可以创建一个简单的组建, 将它们组合在一起并使用该组件.
总结
正如我之前所说的, 我对于这个新的 API 非常的振奋. 这个 API 目前没有发布, 但是一个会包含在下一个发布的 React minor 版本中. 不同担心, 之前的 API 会继续正常工作, 直到下一个 major 版本发布. 所以, 每个人都有时间迁移. 还有不要忘了, React 团队在 Facebook 有超过 50,000 个 React components 需要维护, 所以, 将来很有可能会发布一个 codemod 去自动更新大多数人的代码(就像之前的版本一样).
我对这个新 API 所能提供的东西感到兴奋. 正如我最近在 Twitter 上提到的 https://twitter.com/kentcdodds/status/956675313966239745 (回应 Dan Abramov https://medium.com/@dan_abramov 的 推文 https://twitter.com/dan_abramov/status/956674265104953344 ): 有太多的期待了! 祝你好运!
不容错过的事:
react-broadcast 是 Michael Jackson https://medium.com/@mjackson 的一个库, 提供与 context 同样的功能. 下一个版本 https://github.com/ReactTraining/react-broadcast/tree/next 将是对于
React.createContext
(对 eJames Kyle https://medium.com/@thejameskyle 的 shoutout 以及创建
create-react-context
). 我实际上使用 react-broadcast 在我的高级 react 课程中 https://egghead.io/courses/advanced-react-component-patterns 当新的 contextAPI 正式发布时我将不得不更新 .
react-fns: 浏览器 API 由 Jared Palmer https://medium.com/@jaredpalmer 转变为声明性 React 组件和 HoC's
react-composer: 由 https://medium.com/@jmeas 撰写渲染道具组件(我在上面的代码框中使用的)
react-contextual: Paul Henschel https://medium.com/@drcmda Paul Henschel 的 Reacts 新 context API 的小助手
来源: https://juejin.im/entry/5b619a5ef265da0f9c67baa4