
这是关于React上下文与TypeScript的系列文章中的第二篇。在上一篇文章中,我们创建了一个简单的上下文,TypeScript能够推断其类型:
- 第1部分 -带有函数组件的简单上下文
- 第2部分 -带有函数组件的复杂上下文(这篇文章)
- 第3部分 -带有类组件的上下文
- 第4部分 -创建一个没有默认和未定义检查的上下文
在这篇文章中,我们将实现一个更复杂的上下文,我们需要明确指定上下文类型。
明确设置上下文类型
我们将加强上一篇文章中的上下文,以便消费者可以更新主题。
在上一篇文章中,上下文的类型是从默认值推断出来的,也就是一个简单的string 。我们增强的上下文的类型会更复杂一些:
type ThemeContextType = {
theme: string;
setTheme: (value: string) => void;
};
因此,将有一个theme 属性,包含主题的当前值和一个setTheme 方法来更新当前主题。
ReactscreateContext 函数希望我们为初始上下文值提供一个参数。我们可以为theme 属性提供一个默认值,但为setTheme 方法提供一个默认实现是没有意义的。所以,一个简单的方法是传入undefined 作为初始值:
const ThemeContext = React.createContext(
undefined
);
我们来看看上下文值的推断类型是什么。

如果在严格模式下,上下文值的类型被推断为undefined ,如果不是,则推断为any 。
所以,ThemeContext 目前还没有按照我们的要求进行类型化。在使用createContext 时,我们怎样才能明确指定上下文的类型呢?嗯,createContext 是一个通用函数。所以,我们可以把上下文值的类型作为一个通用参数传入:
const context = React.createContext<ContextType>(...)
因此,我们可以将我们的上下文类型定为如下:
const ThemeContext = React.createContext<
ThemeContextType | undefined
>(undefined);
在提供者中使用增强的上下文
在上一篇文章中,对上下文提供者的修改是对我们从它那里提供的值的修改。它不再是一个简单的string ,现在是一个包含theme 属性和setTheme 方法的对象:
export const ThemeProvider = ({
children
}: Props) => {
...
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
};
在Header 组件中添加一个选项来改变主题
useTheme 自定义钩子与上一篇文章中的保持一致。App 组件也保持不变。
但我们要改变Header 组件,以便用户可以改变主题:
const Header = () => {
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>
);
};
我们取消了当前的主题值以及useTheme 钩子的setTheme 方法。注意,我们在调用useTheme 钩子后加了一个感叹号(!),以告诉TypeScript编译器,它的返回值不会是undefined 。
我们还添加了一个下拉选项,可以将主题改为白色、蓝色和绿色。下拉菜单的值被设置为当前的主题值,当它被改变时,它会调用contextssetTheme 方法来更新共享状态中的内容。
点击下面的链接,可以获得完整的上下文实现。试一试,改变主题值,看看背景的颜色变化。
总结
一般来说,我们需要为上下文创建一个类型,并在创建上下文时明确定义该类型。通常情况下,上下文的初始值是undefined ,所以上下文类型通常是一个包含undefined 的联合类型。在引用上下文时,我们需要使用非空断言操作符(!)来告诉TypeScript它确实有一个值。
在本系列的第四篇文章中,我们将介绍一种不必向上下文传递默认值的方法,并且不必处理它可能是undefined 。在这之前,在下一篇文章中,我们将学习如何用类组件来消费强类型的上下文。