本文介绍一下 React 中常见的 Context API 的使用方式。在使用 Context API 之前,我们还需要知道为啥要使用。❓
为啥要用 Context API
考虑到组件有可能 层层嵌套 ,在传 props 的过程中,如果书写大量的 ...props
或 propName={this.props.propValue}
会导致代码灰常丑陋 ?:
一层一层下来就像这样:
<App>
<Switcher toggleState={this.state.toggle}>
<Pannel toggleState={props.toggleState}>
<div onClick={handleClick}>{props.toggleState ? '✔' : '❌'}
所以引入 Context API 就可以直接通过上下文跨层级获取数据:
如何使用
- 然后创建 provider ?
- 首先要引入 React 内置的 React Context API ?
- 最后创建 consumer ?
创建 Provider
增加一个名为 ToggleContext.js
的文件作为上下文?,里头定义一系列需要跨层级使用的 state 和 function
import React, { createContext } from 'react'
// 1. 使用 createContext 创建上下文
const ToggleContext = createContext({
toggle: true,
handleToggle: () => {}
})
// 2. 创建 Provider
export class ToggleProvider extends React.Component {
// 注意书写顺序;handleToggle 作为箭头函数不能 bind 因此需要写在上面;如果不喜欢这样的顺序则可以书写普通函数放在下面但记得 bind
handleToggle = () => {
this.setState({ toggle: !this.state.toggle })
}
// 2-1. 重写 state
state = {
toggle: true,
handleToggle: this.handleToggle
}
render() {
// 2-2. 通过 Provider 组件的 value 将 state 提供出去
return (
<ToggleContext.Provider value={this.state}>
{this.props.children}
</ToggleContext.Provider>
)
}
}
// 3. 创建 Consumer
export const ToggleConsumer = ToggleContext.Consumer
上面的代码主要分为三大部分:
// 创建 Context
const ToggleContext = createContext()
// 创建 Provider
export class ToggleProvider extends React.Component {}
// 创建 Consumer
export cnost ToggleConsumer = ToggleContext.Consumer
我们理一下步骤?
- 首先,我们需要引入
createContext
上下文并调用,传入我们希望在其他层级组件中使用的state
和改变state
的方法,注意这里的state
和方法只是一个“骨架”,后面的Provider
会覆盖 - 接下来创建
Provider
这里头维护真正的state
,并通过render
函数里面的Context.Provider
组件的value
属性提供这些方法 - 然后创建
Consumer
,直接导出Context.Consumer
给外部使用即可
使用 Provider
ToggleProvider
组件包装了一系列共享的状态,为了使用这些组件的状态,我们直接将其添加到 App 组件中:
import React from 'react';
import { ToggleProvider } from './ToggleContext' // 1. 获取 Provider
function App() {
// 2-1. 使用 ToggleProvider 组件
// 2-2. 如果有其他组件一样可以共享 state
return (
<ToggleProvider>
<Switcher></Switcher>
{/* 其他组件仍然可以通过 props 访问到共享的 state */}
</ToggleProvider>
);
}
// ...
export default App;
使用 Provider 比较简单直接作为父组件包裹在上层即可。如果组件内部有其他多个组件,这些组件都可以共享 Provider 提供的 state
使用 Consumer
- 通过 Consumer 直接使用 props 传递的 state 属性在 render 函数中渲染即可
- 如果需要调用方法,则可调用 props 传递的函数
import React from 'react';
import { ToggleProvider, ToggleConsumer } from './ToggleContext' // 1. 获取 Provider 和 Consumer
function App() {
return (
<ToggleProvider>
<Switcher></Switcher>
</ToggleProvider>
);
}
const Switcher = () => {
return <Pannel />
}
const Pannel = () => {
// 在多个层级内直接通过 props 获取 state 和方法,调用方法改变 state
return (
<ToggleConsumer>
{({ toggle, handleToggle }) => <div onClick={() => handleToggle()}>{ toggle ? '✔' : '❌'}</div>}
</ToggleConsumer>
)
}
export default App;
直接在子组件内部通过 props 调用即可
小结
另外附上一个简易版的 Context:
- 通过 createContext 创建一个名为 color 的 context
- 通过 Provider 的 value 属性传值
- 通过 Consumer 的 props 接收值
import React, { createContext } from "react";
const { Provider, Consumer } = createContext("color"); // 创建 Context 引用 Provider 和 Consumer
class DeliverComponent extends React.Component {
// 维护一个 state
state = {
color: 'orange',
handleClick: () => {
this.setState({ color: 'red' })
}
}
render() {
return (
<Provider value={this.state}>
<MidComponent />
</Provider>
)
}
}
const MidComponent = () => <Receiver />; // 中间包含多层级的组件
const Receiver = () => ( // 需要使用的后代元素使用 Consumer
<Consumer>
{({ color, handleClick }) => <div style={{ color }} onClick={() => { handleClick() }}> Hello, this is receiver.</div>}
</Consumer>
);
const App = () => <DeliverComponent />;
export default App;
参考:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。