React Context with TypeScript:第1部分 - 带有函数组件的简单上下文

177 阅读3分钟

Photo by mohammad takhsh on Unsplash

React上下文允许一个树上的几个组件共享一些数据。这比通过props在组件树上传递数据更方便。我们如何使用TypeScript来创建一个强类型的上下文?是否有可能做到与函数组件以及类组件一样使用?这是关于这个话题的四篇博文中的第一篇:

在这篇文章中,我们将创建一个强类型的React上下文,并在一个不不改变上下文的函数组件中消耗它。

创建一个上下文

使用上下文的一个常见用例是为应用程序中的组件提供主题信息。我们将在一个上下文中提供一个颜色值,让组件可以使用。

让我们开始使用ReactscreateContext 函数创建我们的主题:

const defaultTheme = "white";
const ThemeContext = React.createContext(
  defaultTheme
);

我们需要为上下文提供一个默认值,在我们的例子中是"white"

上下文的类型被推断为React.Context<string>

Inferred type for a simple context 很好--完全符合我们的要求

创建一个上下文提供者

接下来,我们将创建提供者组件:

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 的返回类型被推断为什么:

Inferred type for context hook

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将以浅蓝色背景出现。

打开工作版本

包裹起来

如果在创建上下文时提供了一个合理的默认值,那么上下文的类型就会被正确推断出来。如果上下文提供的是消费者不改变的值,那么这很好。然而,如果我们想让用户改变主题呢?在这种情况下,我们的上下文需要提供一个更新主题的函数,而这不能作为一个默认值来提供。在一篇文章中,我们将扩展我们的主题上下文,以便消费者可以更新该值。