
这是关于React contextwith TypeScript的系列文章中的另一篇文章。在上一篇文章中,我们创建了一个复杂的上下文,并将其消耗在一个函数组件中:
- 第1部分 -使用函数组件的简单上下文
- 第2部分 -使用函数组件的复杂上下文
- 第3部分 -使用类组件的上下文(本帖)
- 第4部分 -创建一个没有默认和未定义检查的上下文
在这篇文章中,我们将学习如何使用React上下文与类组件。
尝试在类组件中使用上下文钩子
我们将继续使用我们在上一篇文章中创建的上下文,它允许消费者分享和设置一个主题。让我们把Header 组件更新为一个类组件:
class Header extends React.Component {
render() {
const { theme, setTheme } = useTheme()!;
return (
<div style={{ backgroundColor: theme }}>
<select
value={theme}
onChange={e => setTheme(e.currentTarget.value)}
>
<option value="white">White</option>
<option value="lightblue">Blue</option>
<option value="lightgreen">Green</option>
</select>
<span>Hello!</span>
</div>
);
}
}
不过这个实现有一个问题:

钩子只能在函数组件内调用,所以,上面的代码在下面一行会出错:
const { theme, setTheme } = useTheme()!;
使用context 属性
React类组件有一个context 属性,我们可以用它来消耗一个上下文。首先,我们需要用static contextType 属性告诉类应该使用什么上下文,然后我们可以访问context 属性:
class Header extends React.Component {
static contextType = ThemeContext;
render() {
const { theme, setTheme } = this.context!;
return (
...
);
}
}
注意,我们在context 属性后面加了一个感叹号(!),以告诉TypeScript编译器,它不是undefined 。
让我们看看theme 和setTheme 被推断为什么类型。

theme 和setTheme 都被推断为具有any 类型。
明确设置context 属性的类型
目前,消耗的上下文并不是强类型的。我们可以用类型注解显式地定义类context 属性,使其成为强类型的:
class Header extends React.Component {
static contextType = ThemeContext;
context: React.ContextType<typeof ThemeContext>;
render() {
const { theme, setTheme } = this.context!;
return (
...
);
}
}
请注意,我们没有使用React.ContextType<ThemeContextType> 作为context 属性的类型注解,因为如果我们这样做,我们会得到一个类型错误。
点击下面的链接,可以得到一个完整的工作实现。试一试,改变主题值,看看背景的颜色变化。
使用Consumer 组件
如果我们只需要在JSX中访问上下文,还有另一种方法来消耗类组件中的上下文。这种方法是使用contextsConsumer 组件:
class Header extends React.Component {
render() {
return (
<ThemeContext.Consumer> {value => (
<div style={{ backgroundColor: value!.theme }}>
<select
value={value!.theme}
onChange={e => value!.setTheme(e.currentTarget.value)}
>
<option value="white">White</option>
<option value="lightblue">Blue</option>
<option value="lightgreen">Green</option>
</select>
<span>Hello!</span>
</div>
)}
</ThemeContext.Consumer> );
}
}
Consumer 组件的孩子是一个函数,它有传入上下文的值,并返回我们想要渲染的JJSX。注意,我们在引用value 后加了一个感叹号(!),以告诉TypeScript编译器这不是undefined 。
这种方法的好处是,contextType 静态属性不需要被实现。我们不需要用类型注解来声明context 属性。
让我们检查一下Consumer 组件子函数中的value 参数的推断类型。

value 参数的类型是ThemeContextType | undefined
包裹起来
我们可以在类组件中使用Reacts上下文,但我们不能使用useContext 钩子。
使用Consumer 组件是一种整洁的方式,可以在render 方法中获得上下文,它的类型被正确推断。
context 属性可以在其他生命周期方法中使用,以获得对上下文的访问。我们需要为context 属性明确地定义一个类型注解,并在contextType 静态属性中指定具体的上下文。
在下一篇文章中,我们将了解一种创建上下文的方法,而不必传递默认值,然后在消费它时做任何undefined 检查。