抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

介绍

在应用开发中,通常会存在一些全局性的内容,例如用户 id、主题、语言、以及各种 token

要保证这些数据的传递,以传统的方式,通常有两种办法:

  • 如果直接使用普通的对象,那么 React 就不会帮你自动更新 UI;
  • 通过 props 的层层注入,需要修改大量的组件,且容易使得代码难以维护。

通过 上下文(Context) 就可以解决这些问题。

定义上下文

使用 React.createContext(默认值) 就可以定义一个上下文:

1
const Config = React.createContext({theme: 'light'});

默认情况下,上下文在浏览器中显示为 Context,如果希望修改 React DevTool 显示的名称,可以修改实例的 displayName 属性:

1
Config.displayName = 'Config';

使用上下文

每个 Context 对象都会返回一个 Provider 组件,它允许里面的子组件订阅 context 的变化。[1]

Provider 需要接收一个 value 属性,当其发生变化时,所有子组件将会重新渲染。[1:1]

对于需要接受数据的类组件,需要定义一个静态属性 contextType 指向Context 对象,然后就可以通过 this.context 使用上下文中的数据了。

我们看一个具体的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const config = { theme: "light" };
const Config = React.createContext(config);
function App() {
return (
<Config.Provider value={config}>
<NavBar />
</Config.Provider>
);
}

function NavBar() {
return <ThemedButton />;
}

class ThemedButton extends React.Component {
static contextType = Config;
render() {
return <button>{this.context.theme}</button>;
}
}

如果组件中的 context 找不到上层的 Provider,那么 组件中的 context 将使用createContext提供的默认值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const config = { theme: "light" };
const Config = React.createContext(config);
function App() {
return (
<React.Fragment>
<Config.Provider value={{ theme: "dark" }}>
<NavBar />
</Config.Provider>
<NavBar />
</React.Fragment>
);
}

function NavBar() {
return <ThemedButton />;
}

class ThemedButton extends React.Component {
static contextType = Config;
render() {
return <button>{this.context.theme}</button>;
}
}

这个案例中,第一个按钮在一个 Provider 下,显示为 dark,第二个则没有在一个 Provider下,显示为 light

监听状态的变更

每个上下文对象具有一个 Consumer 属性,用来订阅 context 的变更。

它的子元素应该是一个函数,参数为 value,返回值为React Dom

1
2
3
<Config.Consumer>
{value => /* 基于 context 值进行渲染*/}
</Config.Consumer>

实例:修改主题

下面一个例子,演示了如何在嵌套的组件中修改主题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const config = { theme: "light", setTheme: () => null };
const Config = React.createContext(config);
Config.displayName = "Config";

class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: "dark",
};
}

render() {
let setTheme = () =>
this.setState({ theme: this.state.theme === "dark" ? "light" : "dark" });
return (
<React.Fragment>
<Config.Provider value={{ theme: this.state.theme, setTheme }}>
<NavBar />
</Config.Provider>
</React.Fragment>
);
}
}

function NavBar() {
return <ThemedButton />;
}

class ThemedButton extends React.Component {
static contextType = Config;
render() {
return (
<button {...this.props} onClick={() => this.context.setTheme()}>
{this.context.theme}
</button>
);
}
}

  1. Context ↩︎ ↩︎

评论