
React上下文允许一个树上的几个组件共享一些数据。这比通过props在组件树上传递数据更方便。我们如何使用TypeScript来创建一个强类型的上下文?是否有可能做到与函数组件以及类组件一样使用?这是关于这个话题的四篇博文中的第一篇:
- 第1部分 -使用函数组件的简单上下文(这篇文章)
- 第2部分 -使用函数组件的复杂上下文
- 第3部分 -使用类组件的上下文
- 第4部分 -创建一个没有默认和未定义检查的上下文
在这篇文章中,我们将创建一个强类型的React上下文,并在一个不不改变上下文的函数组件中消耗它。
创建一个上下文
使用上下文的一个常见用例是为应用程序中的组件提供主题信息。我们将在一个上下文中提供一个颜色值,让组件可以使用。
让我们开始使用ReactscreateContext 函数创建我们的主题:
const defaultTheme = "white";
const ThemeContext = React.createContext(
defaultTheme
);
我们需要为上下文提供一个默认值,在我们的例子中是"white" 。
上下文的类型被推断为React.Context<string> 。
很好--完全符合我们的要求
创建一个上下文提供者
接下来,我们将创建提供者组件:
type Props = {
children: React.ReactNode
};
export const ThemeProvider = ({
children
}: Props) => {
const [theme, setTheme] = React.useState(
defaultTheme
);
React.useEffect(() => {
// We'd get the theme from a web API / local storage in a real app
// We've hardcoded the theme in our example
const currentTheme = "lightblue";
setTheme(currentTheme);
}, []);
return (
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
);
};
我们在状态中保存主题值。这意味着当它发生变化时,React会自动用新的主题重新渲染提供者的孩子。
我们使用ReactsuseEffect 钩子获得当前主题值,并更新theme 状态值。
出来的主题提供者组件在上下文中用我们的主题值返回Provider 组件。提供者被包裹在组件树中的所有孩子身上。
创建一个用于消费上下文的自定义钩子
我们可以创建一个自定义钩子,让函数组件消耗我们的上下文:
export const useTheme = () =>
React.useContext(ThemeContext);
让我们检查一下useTheme 的返回类型被推断为什么:

useTheme 的返回类型是string ,因为这是上下文值的类型。
将提供者添加到组件树中
现在,ThemeProvider 组件可以被放置在组件树中的适当位置:
const App = () => (
<ThemeProvider>
<Header />
</ThemeProvider>
);
它下面的组件可以访问上下文,但它上面的组件则不能。因此,Header 组件将可以访问上下文。
消耗上下文
Header 组件可以通过使用我们创建的useTheme 钩子访问上下文。这允许头顶组件渲染一个背景颜色设置为主题颜色的元素:
const Header = () => {
const theme = useTheme();
return (
<div style={{ backgroundColor: theme }}>
Hello!
</div>
);
};
点击下面的链接,可以获得ThemeContext 的工作版本。当应用程序运行时,Hello将以浅蓝色背景出现。
包裹起来
如果在创建上下文时提供了一个合理的默认值,那么上下文的类型就会被正确推断出来。如果上下文提供的是消费者不改变的值,那么这很好。然而,如果我们想让用户改变主题呢?在这种情况下,我们的上下文需要提供一个更新主题的函数,而这不能作为一个默认值来提供。在下一篇文章中,我们将扩展我们的主题上下文,以便消费者可以更新该值。