了解React的新上下文API
介绍
在一个有很多不同前端框架的世界里,总是很难知道该选择哪一个。 我想使用曾经流行的 Angular 吗? 或者深入研究 VueJS 是否对我的知识范围有益?
然后我们有 ReactJS,一个由 Facebook 创建的框架,似乎正在席卷前端框架世界。 使用组件、虚拟 DOM 和 JSX(这是不同的一天!),React 似乎涵盖了所有内容,使其成为一个强大的框架。
最近在 React 16.3 中引入了新的 Context API:
一种通过组件树传递数据而无需在每个级别手动向下传递道具的方法
听起来很棒! 让我们深入挖掘。
道具和状态
在 React 中,你有 props
和 state
。 两件非常重要的事情要理解。
Props 是属性的缩写,是从父组件传递给组件的数据。
State 是在组件内管理的数据。 因此,如果每个组件都有自己的状态,我们如何将这些信息共享给另一个组件? 你可以使用 props,但 props 只能在父组件和子组件之间传递。
那么,如果我们有很多层的组件来传递一点信息,我们该怎么办呢? 也称为螺旋钻?
道具钻探(上下文 API 解决的问题)
让我们看一个 prop-drilling 的示例,以便我们了解 Context API 正在解决什么问题。 在本例中,我们将看到如何将信息从一个组件传递到子组件,然后再传递到该组件的子组件。
const Lowest = (props) => ( <div className="lowest">{props.name}</div> ) const Middle = (props) => ( <div className="middle"> <Lowest name={props.name} /> </div> ) class Highest extends Component { state = { name: "Context API" } render() { return <div className="highest"> {this.state.name} <Middle name={this.state.name} /> </div> } }
我知道命名并不是最真实的,但它有助于展示上下文传递给嵌套组件的能力。 更真实的情况是可能发生在基于卡的用户界面中:CardGrid
-> CardContent
-> CardFooter
-> LikeButton
。
回到我们的示例,这就是 Highest
-> Middle
-> Lowest
组件的嵌套方式:
<Highest> <Middle> <Lowest> {/* we want our content here but dont want to prop pass ALLLL the way down ! */} </Lowest> </Middle> </Highest>
请注意,为了让最高者和最低者交谈,他们需要中间人作为信使吗?
你瞧,我们有 React Context 可以为我们处理所有的工作。
React 的上下文 API
React Context 允许我们拥有一个可以在整个应用程序 全局范围内看到的状态 。
我们必须从上下文提供者 (<Provider />
) 开始定义要发送的数据,并且需要上下文消费者 (<Consumer />
) 来获取该数据并在调用时使用它。
使用 Context,您现在可以声明一次状态,然后通过上下文使用者在应用程序的每个部分使用该数据。
听起来不可思议,对吧? 好吧,让我们看看如何在一个简单的 React 应用程序中进行设置。
让我们建造吧!
使用 Context API 构建名称传输
今天我们将设置一个基本的 React 应用程序。 让我们做一个应用程序,将名称从一个组件传递到另一个恰好不是子组件的组件! 伟大的! 我们将有三个不同的级别,一个是名称存储在状态中的最高组件,我们将拥有中间组件,然后我们将拥有最低组件。
我们的应用程序会将状态中的名称从最高到最低发送,而无需与中间对话。 打开您喜欢使用的任何代码编辑器,让我们开始编码吧!
首先,我们的应用需要 react
依赖项。 继续并将其添加到您的依赖项中,或者如果您在文本编辑器中工作,请执行以下步骤来安装它:
- 如果您还没有 npm,请在您的机器上全局安装它。
npm install —save react
- 检查您的 package.json 中的
react
依赖项。
在我们的主 .js
文件中,这就是魔法发生的地方。 每当我们构建一个 React 应用程序时,您总是需要导入您的依赖项,否则该文件将不知道使用它。 所以在 index.js
文件的顶部,让我们导入我们需要的内容:
import React, { Component } from 'react';
我们有我们的导入,现在让我们继续讨论组件。 为了便于阅读,我们将希望在变量中声明我们的上下文。 在我们的导入下,让我们这样做:
const AppContext = React.createContext()
我们的组件层
我们的 Highest
组件将具有状态。 我们的状态将有一个名称,我们希望将其传递给 Lowest
组件,而不必与 Middle
组件对话:
class Highest extends Component { state = { name : “React Context API”, } render() { return ( <AppContext.Provider value={this.state}> {this.props.children} </AppContext.Provider> ) } }
我们将构建我们的子组件,称为 Middle
组件:
const Middle = () => ( <div> <p>I’m the middle component</p> <Lowest /> </div> )
其子组件将被称为 Lowest
:
const Lowest = () => ( <div> <AppContext.Consumer> {(context) => context.name} </AppContext.Consumer> </div> )
让我们来看看这个。 你会看到我们在 Highest
中有一个我们想要传递给 Lowest
的状态。 我们有我们的 静态属性 ,它将允许我们声明我们希望我们的上下文是什么。 在我们的例子中,名称为“React Context API”。
Provider
保留该数据,以便当它被另一个组件 consumed
时,它知道要给它什么。 在我们的 Lowest
组件中,您将看到我们有 Consumer
想要该数据,而无需先将其传递给 Middle
组件。 相反,该组件只是挂起,声明 Lowest
是它的孩子。
何时不使用上下文
对于可以适当扩展的简单支柱钻孔解决方案,请尝试一下! 对于具有多个(和更复杂)状态、reducer 等的大型应用程序,Redux 可能更适合。
没有必要在整个应用程序中使用上下文,这会使事情变得有点过于混乱。 对你的代码要足智多谋,不要只使用上下文来跳过额外的输入。
结论
React Context API 非常棒。 但除非你知道它对你和你的代码有益,否则不要使用它。 Redux 可能还不错。 远离道具钻探,并知道诸如上下文之类的东西可以帮助您避免这种情况。 这是一个很好的选择!
如果你想查看所有的代码,你可以在codesandbox上得到所有的。