本文介绍一下 React 中常见的 Context API 的使用方式。在使用 Context API 之前,我们还需要知道为啥要使用。❓
考虑到组件有可能 层层嵌套 ,在传 props 的过程中,如果书写大量的 ...props
或 propName={this.props.propValue}
会导致代码灰常丑陋 ?:
20190312085239.png
一层一层下来就像这样:
1<App>
2 <Switcher toggleState={this.state.toggle}>
3 <Pannel toggleState={props.toggleState}>
4 <div onClick={handleClick}>{props.toggleState ? '✔' : '❌'}
所以引入 Context API 就可以直接通过上下文跨层级获取数据:
增加一个名为 ToggleContext.js
的文件作为上下文?,里头定义一系列需要跨层级使用的 state 和 function
1import React, { createContext } from 'react'
2
3// 1. 使用 createContext 创建上下文
4const ToggleContext = createContext({
5 toggle: true,
6 handleToggle: () => {}
7})
8
9// 2. 创建 Provider
10export class ToggleProvider extends React.Component {
11
12 // 注意书写顺序;handleToggle 作为箭头函数不能 bind 因此需要写在上面;如果不喜欢这样的顺序则可以书写普通函数放在下面但记得 bind
13 handleToggle = () => {
14 this.setState({ toggle: !this.state.toggle })
15 }
16
17 // 2-1. 重写 state
18 state = {
19 toggle: true,
20 handleToggle: this.handleToggle
21 }
22
23 render() {
24 // 2-2. 通过 Provider 组件的 value 将 state 提供出去
25 return (
26 <ToggleContext.Provider value={this.state}>
27 {this.props.children}
28 </ToggleContext.Provider>
29 )
30 }
31}
32
33// 3. 创建 Consumer
34export const ToggleConsumer = ToggleContext.Consumer
35
上面的代码主要分为三大部分:
1// 创建 Context
2const ToggleContext = createContext()
3
4// 创建 Provider
5export class ToggleProvider extends React.Component {}
6
7// 创建 Consumer
8export cnost ToggleConsumer = ToggleContext.Consumer
我们理一下步骤?
createContext
上下文并调用,传入我们希望在其他层级组件中使用的 state
和改变 state
的方法,注意这里的 state
和方法只是一个“骨架”,后面的 Provider
会覆盖Provider
这里头维护真正的 state
,并通过 render
函数里面的 Context.Provider
组件的 value
属性提供这些方法Consumer
,直接导出 Context.Consumer
给外部使用即可ToggleProvider
组件包装了一系列共享的状态,为了使用这些组件的状态,我们直接将其添加到 App 组件中:
1import React from 'react';
2import { ToggleProvider } from './ToggleContext' // 1. 获取 Provider
3
4function App() {
5 // 2-1. 使用 ToggleProvider 组件
6 // 2-2. 如果有其他组件一样可以共享 state
7 return (
8 <ToggleProvider>
9 <Switcher></Switcher>
10 {/* 其他组件仍然可以通过 props 访问到共享的 state */}
11 </ToggleProvider>
12 );
13}
14
15// ...
16export default App;
使用 Provider 比较简单直接作为父组件包裹在上层即可。如果组件内部有其他多个组件,这些组件都可以共享 Provider 提供的 state
1import React from 'react';
2import { ToggleProvider, ToggleConsumer } from './ToggleContext' // 1. 获取 Provider 和 Consumer
3
4function App() {
5 return (
6 <ToggleProvider>
7 <Switcher></Switcher>
8 </ToggleProvider>
9 );
10}
11
12const Switcher = () => {
13 return <Pannel />
14}
15
16const Pannel = () => {
17 // 在多个层级内直接通过 props 获取 state 和方法,调用方法改变 state
18 return (
19 <ToggleConsumer>
20 {({ toggle, handleToggle }) => <div onClick={() => handleToggle()}>{ toggle ? '✔' : '❌'}</div>}
21 </ToggleConsumer>
22 )
23}
24
25export default App;
26
直接在子组件内部通过 props 调用即可
另外附上一个简易版的 Context:
1import React, { createContext } from "react";
2
3const { Provider, Consumer } = createContext("color"); // 创建 Context 引用 Provider 和 Consumer
4
5class DeliverComponent extends React.Component {
6 // 维护一个 state
7 state = {
8 color: 'orange',
9 handleClick: () => {
10 this.setState({ color: 'red' })
11 }
12 }
13 render() {
14 return (
15 <Provider value={this.state}>
16 <MidComponent />
17 </Provider>
18 )
19 }
20}
21
22const MidComponent = () => <Receiver />; // 中间包含多层级的组件
23
24const Receiver = () => ( // 需要使用的后代元素使用 Consumer
25 <Consumer>
26 {({ color, handleClick }) => <div style={{ color }} onClick={() => { handleClick() }}> Hello, this is receiver.</div>}
27 </Consumer>
28);
29
30const App = () => <DeliverComponent />;
31
32export default App;
参考: