
这是关于React上下文与TypeScript的系列文章中的最后一篇文章。在上一篇文章中,我们在一个类组件中消耗了一个上下文。在这篇文章中,我们将学习如何在不需要传递默认值的情况下创建一个上下文,然后在消费它的时候做任何undefined 检查:
- 第1部分 -带有函数组件的简单上下文
- 第2部分 -带有函数组件的复杂上下文
- 第3部分 -带有类组件的上下文
- 第4部分 -创建一个没有默认值和没有未定义检查的上下文(这篇文章)
问题所在
createContext 的类型要求向其传递一个默认值,但通常情况下,传递一个默认值并没有意义。所以,我们最终把undefined 作为默认值:
const ThemeContext = React.createContext<
ThemeContextType | undefined
>(undefined);
...然后在我们使用它的地方检查undefined :
const { theme, setTheme } = useTheme()!;
一个快速的解决方案
这个问题的一个快速解决方案是使用not-null断言操作符,并从上下文类型中删除undefined :
const ThemeContext = React.createContext<
ThemeContextType
>(undefined!);
这样做很好,因为消费代码不需要undefined 检查。然而,我们仍然在传递一个默认值。
创建一个用于创建上下文的包装器
一个解决方案是在createContext 上创建一个包装器,处理默认值和undefined 检查:
export function createCtx<ContextType>() {
const ctx = React.createContext<
ContextType | undefined
>(undefined);
function useCtx() {
const c = React.useContext(ctx);
if (!c)
throw new Error(
"useCtx must be inside a Provider with a value"
);
return c;
}
return [useCtx, ctx.Provider] as const;
}
这个函数首先用传入的通用类型创建上下文,并将undefined 作为其默认值。
然后定义一个嵌套函数,它包裹了useContext 钩子。一个变量c 被分配给useContext 钩子的返回值,即传入的通用类型或undefined 。

然后,如果c 是错误的,我们就抛出一个错误,这就处理了undefined 的检查。这意味着当c 从嵌套函数返回时,它不能undefined ,只能是我们传入的通用类型:

注意我们在最后一行使用了一个const断言(as const),以确保TypeScript推断出一个元组类型,而不是一个联合类型的数组。
创建一个上下文
我们现在可以使用我们的createCtx 函数来创建一个上下文,而不是React的createContext :
const [useTheme, CtxProvider] = createCtx<
ThemeContextType
>();
创建一个提供者
我们的createCtx 函数返回一个元组,该元组在第二个元素中包含一个提供者组件 (CtxProvider)。我们可以创建包含我们所需状态的特定提供者组件:
export const ThemeProvider = ({
children
}: Props) => {
const [theme, setTheme] = React.useState(
"white"
);
...
return (
<CtxProvider value={{ theme, setTheme }}> {children}
</CtxProvider> );
};
然后,这可以被放置在组件树中的适当位置:
export const App = () => (
<ThemeProvider> <Header />
</ThemeProvider>);
消耗上下文
我们的createCtx 也在图元的第一个元素中返回一个钩子(useTheme)。我们可以使用它而不需要做任何undefined 检查:
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>
);
};
很好!
点击下面的链接,可以得到一个完整的工作实现。试一试,改变主题值,看看背景的颜色变化。
总结
createCtx 函数是一个通用函数,可以用来为许多情况创建上下文。它简化了消耗的代码,因为不需要对undefined 的检查。
这就是关于React上下文与TypeScript的系列文章的结尾。我希望你喜欢它!