第 5 章 实现 React Context

第 5 章 实现 React Context

Flying
2021-02-06 / 0 评论 / 226 阅读 / 正在检测是否收录...

在前面的章节中,我们学习了最基本的 Hook,例如 State Hook、Reducer Hook 和 Effect Hook。我们使用这些 Hook 开发了一个小型博客应用程序。在博客应用程序的开发过程中我们注意到,我们必须将 user 状态从 App 组件传递到 UserBar 组件,从 UserBar 组件传递 LoginRegisterLogout 组件。为了避免像这样传递状态,我们现在将学习 React Context 和 Context Hook。

在本章中,我们将从学习 React Context 是什么,以及 provider 和 consumer 是什么开始。然后,我们将使用 Context Hooks 作为 Context consumer,并讨论何时应该使用 Context。最后,我们将通过 Context 实现主题和全局状态。

本章将介绍以下主题:

  • 引入 React context 作为传递 props 的替代方案
  • 通过 context 实现主题
  • 使用全局状态的 context

技术要求

应该已经安装了相当新版本的 Node.js(vl1.l2.0 或更高版本)。还需要安装 Node.js 的 npm 包管理器。

本章的代码可以在 GitHub 存储库中找到:https://github.com/PacktPublishing/Learn-React-Hooks/tree/master/Chapter05

观看以下视频,了解代码的实际应用:

http://bit.ly/2Mm9yoC

请注意,强烈建议您自己编写代码。不要简单地运行已提供的代码示例。重要的是你自己编写代码,以便你能够正确学习和理解。但是,如果遇到任何问题,始终可以参考代码示例。

现在,让我们从本章开始。

介绍 React Context

在前面的章节中,我们将 user 状态和 dispatch 函数从 App 组件传递给了 UserBar 组件;然后从 UserBar 组件转到 LogoutLoginRegister 组件。React Context 为这种在多个级别的组件上传递 props 的繁琐方式提供了一种解决方案,它允许我们在组件之间共享值,而不必通过 props 显式传递它们。正如我们将要看到的,React Context 非常适合在整个应用程序中共享值。

首先,我们将仔细研究 props 的传递问题。然后,我们将引入 React Context 作为问题的解决方案。

传递 Props

在深入学习 React Context 之前,让我们回顾一下我们在前面章节中实现的内容,以便了解 context 解决的问题:

  1. src/App.js 中,我们定义了 user 状态和 dispatch 函数:
const [ state, dispatch ] = useReducer(appReducer, { user: '', posts: defaultPosts })
const { user, posts } = state
  1. 然后,我们将 user 状态和 dispatch 函数传递给 UserBar 组件(和 CreatePost 组件):
return (
  <div style={{ padding: 8 }}>
    <UserBar user={user} dispatch={dispatch} />
    {user && <CreatePost
      user={user}
      posts={posts}
      dispatch={dispatch}
    />}
    <hr />
    <PostList posts={posts} />
  </div>
)
  1. src/user/UserBar.js 组件中,我们将 user 状态作为 prop,然后将其传递给 Logout 组件。我们还将 dispatch 函数作为一个 prop,并将其传递给 LogoutLoginRegister 组件:
export default function UserBar({ user, dispatch }) {
  if (user) {
    return <Logout user={user} dispatch={dispatch} />
  } else {
    return (
      <React.Fragment>
        <Login dispatch={dispatch} />
        <Register dispatch={dispatch} />
      </React.Fragment>
    )
  }
}
  1. 最后,我们在 LogoutLoginRegister 组件中使用了 dispatchuser 属性。

React Context 允许我们跳过步骤 2 和 3,直接从步骤 l 跳到步骤 4。可以想象,对于更大的应用程序,Context 变得更加有用,因为我们可能不得不在许多级别上传递 props。

介绍 React Context

React Context 用于在 React 组件树中共享值。通常,我们希望共享全局值,例如 user 状态和 dispatch 函数、应用程序的主题或所选语言。

React Context 由两部分组成:

  • provider,提供(设置)值
  • consumer,消费(使用)值

我们将首先使用一个简单的示例来了解 context 的工作原理,在下一节中,我们将在我们的博客应用程序中实现它们。我们也使用 create-react-app 创建了一个新项目。在我们的简单示例中,我们将定义一个主题 context,其中包含应用程序的主要颜色。

定义 Context

首先,我们必须定义 context。自引入 Hook 以来,这种工作方式一直没有改变。

我们只需使用 React.createContext(defaultValue) 函数来创建一个新的 context 对象。我们将默认值设置为 { primaryColor: 'deepskyblue' },因此当未定义 provider 时,我们的主要颜色默认为 deepskyblue

src/App.js 中,在 App 函数之前添加以下定义:

export const ThemeContext = React.createContext({ primaryColor: 'deepskyblue' })
请注意我们如何在此处导出 ThemeContext,因为我们需要为 consumer 导入它。

这就是我们使用 React 定义 context 所需要做的一切。现在我们只需要定义 consumer。

定义 Consumer

现在,我们必须在 Header 组件中定义 consumer 。我们现在将以传统方式执行此操作,在接下来的步骤中,使用 Hook 来定义 consumer:

  1. 创建新的 src/Header.js 文件
  2. 首先,我们必须从 App.js 文件中导入 ThemeContext
import React from 'react'
import { ThemeContext } from './App'
  1. 现在,我们可以定义组件,其中我们使用 ThemeContext.Consumer 组件和一个 render 函数作为 children prop,以便使用 context 值:
const Header = ({ text }) => (
  <Themecontext.consumer>
    {theme => (
  1. render 函数中,我们现在可以使用 context 值来设置 Header 组件的 color 样式:
    <h1 style={{ color: theme.primarycolor }}>{text}</h1>
  )}
  </ThemeContext.Consumer>
)

export default Header
  1. 现在,我们仍然需要通过添加以下 import 语句在 src/App.js 中导入 Header 组件:
import Header from './Header'
  1. 然后,我们将当前的 App 函数替换为以下代码:
const App = () => (
  <Header text="Hello World" />
)

export default App

使用这样的 context 是有效的,但是,正如我们在第一章中学到的,以这种方式使用带有 render 函数 props 的组件会使我们的 UI 树混乱,并使我们的应用程序更难调试和维护。

使用 Hook

使用 context 的更好方法是使用 useContext Hook!这样,我们可以像使用任何其他值一样使用 context 值,其方式与 useState Hook 类似:

  1. 编辑 src/Header.js。首先,我们从 React 导入 useContext Hook,从 src/App 导入 ThemeContext 对象:
import React, { useContext } from 'react'
import { Themecontext } from './App'
  1. 然后,我们创建 Header 组件,现在我们在其中定义 useContext Hook:
const Header = ({ text }) => {
  const theme = useContext(Themecontext)
  1. 我们组件的其余部分将与以前相同,只是现在我们可以简单地返回我们的 Header 组件,而无需为 consumer 使用额外的组件:
  return <h1 style={{ color: theme.primarycolor }}>{text}</h1>
}

export default Header

正如我们所看到的, Hook 的使用让我们的 context consumer 代码更加简洁。此外,它将更易于阅读、维护和调试。

我们可以看到标题现在的颜色是深天蓝:

context-hook-app.jpg
使用 Context Hook 的简单应用程序

如我们所见,我们的主题 context 成功地为标题提供了主题。

定义 Provider

context 使用传递给 React.createContext 的默认值,当没有定义 provider 时。这对于调试未嵌入到应用程序中的组件非常有用。例如,我们可以将单个组件作为独立组件进行调试。在应用程序中,我们通常希望使用 provider 来提供 context 的值,我们现在将定义该值。

编辑 src/App.js ,在 App 函数中,我们简单地将 Header 组件与 <ThemeContext.Provider> 组件包装在一起,其中我们将 coral 作为 primaryColor 传递:

const App = () => (
  <Themecontext.Provider value={{ primarycolor: 'coral' }}>
    <Header text="Hello World" />
  </Themecontext.Provider>
)

export default App

现在我们可以看到标题颜色从深天蓝色变为珊瑚色:

provider-simple.jpg
Provider 更改了标题颜色

如果我们想更改 context 的值,我们可以简单地调整传递给 Provider 组件的 value 属性。

请注意,当我们定义一个 provider 而不将 value prop 传递给它时,不会使用 context 的默认值!如果我们定义一个没有 value prop 的 provider,那么 context 的值将是未定义的。

现在我们已经为 context 定义了单个 provider,让我们继续定义多个嵌套的 provider。

嵌套 Provider

使用 React Context,还可以为同一个 context 定义多个 provider。使用此技术,我们可以覆盖应用程序某些部分中的 context 值。让我们考虑前面的示例,并给它添加第二个页眉:

  1. 编辑 src/App.js ,并添加第二个 Header 组件:
const App = () => (
  <ThemeContext.Provider value={{ primaryColor: 'coral' }}>
    <Header text="Hello World" />
    <Header text="This is a test" />
  </ThemeContext.Provider>
)

export default App
  1. 现在,使用不同的 primaryColor 定义第二个 Provider 组件:
const App = () => (
  <ThemeContext.Provider value={{ primaryColor: 'coral' }}>
    <Header text="Hello World" />
    <Themecontext.Provider value={{ primarycolor: 'deepskyblue' }}>
      <Header text="This is a test" />
    </Themecontext.Provider>
  </ThemeContext.Provider>
)

export default App

如果我们在浏览器中打开应用程序,现在第二个标题的颜色与第一个标题的不同:

provider-nested.jpg
使用嵌套 Provider 重写 context 值

如我们所见,我们可以通过定义 provider 来覆盖 React Context 值。provider 也可以嵌套,因此可以覆盖组件树中较高位置的其他 provider 的值。

示例代码

小型主题 context 示例的示例代码可以在 Chapter05/chapter5_1 文件夹中找到。

只需运行 npm install 即可安装所有依赖项,运行 npm start 启动应用程序,然后在您的浏览器中访问 http://localhost:3000(如果它没有自动打开)。

Context 的替代方案

但是,我们应该小心,不要太频繁地使用 React Context,因为它会使重用组件变得更加困难。只有当我们需要访问许多组件中的数据,这些组件处于不同的嵌套级别时才应该使用 context。此外,我们需要确保只对不经常更改的数据使用 context。频繁更改 context 的值可能会导致整个组件树重新渲染,从而导致性能问题。这就是为什么对于频繁变化的值,我们应该改用状态管理解决方案,比如 ReduxMobX

如果我们只想避免传递 props,我们可以传递渲染的组件而不是数据。例如,假设我们有一个 Page 组件,它渲染一个 Header 组件,Header 组件渲染一个 Profile 组件,Profile 组件它渲染一个Avatar 组件。我们得到一个传递给 Page 组件的 headerSize 属性,我们在 Header 组件中需要它,但在 Avatar 组件中也需要它。与其通过多个级别传递 props,我们可以执行以下操作:

function Page ({ headerSize }) {
  const profile = (
    <Profile>
      <Avatar size={headerSize} />
    </Profile>
  )
  return <Header size={headerSize} profile={profile} />
}

现在,只有 Page 组件需要知道 headerSize 属性,并且不需要在树中进一步传递它。在这种情况下,context 不是必需的。

这种模式称为 控制反转,它可以使您的代码比传递 props 或使用 context 更干净。但是,我们也不应该总是使用这种模式,因为它会使更高级别的组件更加复杂。

实现主题

在一个小示例中学习如何实现主题之后,我们现在将使用 React Context 和 Hook 在我们的博客应用程序中实现主题。

定义 Context

首先,我们必须定义 context。在我们的博客应用程序中,我们将为 context 创建一个单独的文件,而不是在 src/App.js 文件中定义它。为 context 使用单独的文件可以更轻松地在以后维护它们。此外,我们始终知道从哪里导入 context,因为从文件名中可以清楚地看出。

让我们开始定义一个主题 context:

  1. 创建一个新的 src/contexts.js 文件。
  2. 然后,我们导入 React
import React from 'react'
  1. 接下来,我们定义 ThemeContext。与之前的小示例中一样,我们将默认的 primaryColor 设置为 deepskyblue。此外,我们将secondaryColor 设置为 coral
export const ThemeContext = React.createContext({
  primaryColor: 'deepskyblue',
  secondaryColor: 'coral'
})

现在我们已经定义了 context,我们可以继续定义 Context Hook。

定义 Context Hook

定义 context 后,我们将使用 Context Hook 定义我们的 consumer。首先为 Header 创建一个新组件,然后为现有的 Post 组件定义一个 Context Hook。

创建 Header 组件

首先,我们创建一个新的 Header 组件,它将用我们应用程序的 primaryColor 色显示 React Hooks Blog

现在让我们创建 Header 组件:

  1. 创建一个新的 src/Header.js 文件。
  2. 在这个文件中,我们导入了 React,以及 useContext Hook:
import React, { useContext } from 'react'
  1. 接下来,我们从之前创建的 src/contexts.js 文件中导入 ThemeContext
import { ThemeContext } from ''./contexts'
  1. 然后,我们定义 Header 组件和 Context Hook。我们没有将 context 值存储在 theme 变量中,而是使用解构来直接提取 primaryColor 值:
const Header = ({ text }) => {
  const { primaryColor } = useContext(ThemeContext)
  1. 最后,我们返回 h1 元素,就像我们之前在我们的小示例中所做的那样,并 export Header 组件:
  return <h1 style={{ color: primaryColor }}>{text}</h1>
}

export default Header

现在我们的 Header 组件已经定义,我们可以使用它了。

使用 Header 组件

创建 Header 组件后,我们将在 App 组件中使用它,如下所示:

  1. 编辑 src/App.js ,并导入 Header 组件:
import Header from './Header'
  1. 然后,在 UserBar 组件之前渲染 Header 组件:
return (
  <div style={{ padding: 8 }}>
  <Header text="React Hooks Blog" />
  <UserBar user={user} dispatch={dispatch} />
您可能希望将 React Hooks Blog 值重构为传递给 App 组件(应用程序配置)的 prop,因为我们已经在此组件中使用它三次。

现在,我们的 Header 组件将在应用程序中渲染,我们可以继续在 Post 组件中实现 Context Hook。

实现 Post 组件的 Context Hook

接下来,我们要以次要颜色显示文章标题。为此,我们需要为 Post 组件定义一个 Context Hook,如下所示:

  1. 编辑 src/post/Post.js,并调整 import 语句以导入 useContext Hook:
import React, { useContext } from 'react'
  1. 接下来,我们导入 ThemeContext
import { ThemeContext } from '../contexts'
  1. 然后,我们在 Post 组件中定义一个 Context Hook,并通过解构从主题中获取 secondaryColor 值:
export default function Post ({ title, content, author }) {
  const { secondarycolor } = useContext(Themecontext)
  1. 最后,我们使用 secondaryColor 值来设置 h3 元素的样式:
return (
  <div>
  <h3 style={{ color: secondarycolor }}>{title}</h3>

如果我们现在查看我们的应用程序,我们可以看到来自 ThemeContext 的两种颜色都被正确地使用:

theme-context.jpg
我们的 ThemeContext 实战

正如我们所看到的,我们的应用程序现在给主标题使用主要颜色,给文章标题使用次要颜色。

定义 Provider

现在,我们的 Context Hook 使用 context 指定的默认值,当未定义 provider 时。为了能够更改值,我们需要定义一个 provider。

让我们开始定义 provider:

  1. 编辑 src/App.js ,并导入 ThemeContext
import { ThemeContext } from './contexts'
  1. 使用 ThemeContext.Provider 组件包装整个应用程序,提供我们之前设置为默认值的相同主题:
return (
  <Themecontext.Provider
    value={{ primarycolor: 'deepskyblue', secondarycolor: 'coral' }}>
    <div style={{ padding: 8 }}>
      <Header text="React Hooks Blog" />
      ...
      <PostList posts={posts} />
    </div>
  </Themecontext.Provider>
)

我们的应用程序看起来应该与以前完全相同,但现在我们使用的是 provider 的值!

动态更改主题

现在我们已经定义了一个 provider,我们可以使用它来动态更改主题。我们将使用定义当前主题的 State Hook,而不是将静态值传递给 provider。然后,我们将实现一个更改主题的组件。

在 Context Provider 使用 State Hook

首先,我们将定义一个新的 State Hook,我们将使用它来设置 context provider 的值。

让我们定义一个 State Hook,并在 context provider 中使用它:

  1. 编辑 src/App.js ,并导入 useState Hook:
import React, { useReducer, useEffect, usestate } from 'react'
  1. 在 App 组件的开头定义一个新的 State Hook;在这里,我们将默认值设置为默认主题:
export default function App () {
const [ theme, setTheme ] =
  usestate({ primarycolor: 'deepskyblue', secondarycolor: 'coral' })
  1. 然后,我们将 theme 值传递给 ThemeContext.Provider 组件:
return (
  <ThemeContext.Provider value={theme}>

我们的应用程序看起来仍然和以前一样,但我们现在准备好动态更改我们的主题了!

实现 ChangeTheme 组件

主题功能的最后一部分是一个组件,可用于使用我们之前定义的 State Hook 来动态更改主题。State Hook 将重新渲染 App 组件,这将更改传递给 ThemeContext.Provider 的值,而 ThemeContext.Provider 又将重新渲染使用 ThemeContext Context Hook 的所有组件。

让我们开始实现 ChangeTheme 组件:

  1. 创建一个新的 src/ChangeTheme.js 文件。
  2. 与往常一样,我们必须先导入 React,然后才能定义组件:
import React from 'react'
  1. 为了能够在以后轻松添加新主题,我们将创建一个常量 THEMES 数组,而不是手动复制和粘贴不同主题的代码。这将使我们的代码更加简洁,更易于阅读:
const THEMES = [
  { primaryColor: 'deepskyblue', secondaryColor: 'coral' },
  { primaryColor: 'orchid', secondaryColor: 'mediumseagreen' }
]
最好为硬编码的常量值指定一个特殊名称,例如将整个变量名称写成大写字母。稍后,将所有这些可配置的硬编码值放在单独的 src/config.js 文件中可能是有意义的。
  1. 接下来,我们定义一个组件来渲染单个 theme
function Themeitem ({ theme, active, onClick }) {
  1. 在这里,我们通过显示主要和次要颜色来渲染一个链接,并显示主题的小预览:
return (
    <span onClick={onClick}
      style={{ cursor: 'pointer', paddingLeft: 8, fontWeight: active ? 'bold' : 'normal' }}>
      <span style={{ color: theme.primaryColor }}>Primary</span>
      <span style={{ color: theme.secondaryColor }}>Secondary</span>
    </span>
  )
}
在这里,我们将光标设置为指针,以使元素看起来可单击。我们也可以使用一个元素;但是,如果我们没有有效的链接目标(例如单独的页面),则不建议这样做。
  1. 然后,我们定义 ChangeTheme 组件,它接受 themesetTheme props:
export default function ChangeTheme ({ theme, setTheme }) {
  1. 接下来,我们定义一个函数来检查主题对象是否是当前活动的主题:
function isActive (t) {
  return t.primaryColor === theme.primaryColor &&
    t.secondaryColor === theme secondaryColor
}
  1. 现在,我们使用 map 函数渲染所有可用的主题,并在单击它们时调用 setTheme 函数:
return (
  <div>

更改主题:

{THEMES.map((t, i) =>
  <Themeitem key={'theme-' + i} theme={t}
    active={isActive(t)} onClick={() => setTheme(t)}
  />
)}
</div>
)}
  1. 最后,我们可以在 src/App.js 中的 Header 组件之后导入并渲染 ChangeTheme 组件:
import ChangeTheme from './ChangeTheme'
// ...
return (
  <ThemeContext.Provider value={theme}>
    <div style={{ padding: 8 }}>
    <Header text="React Hooks Blog" />
    <changeTheme theme={theme} setTheme={setTheme} />

如我们所见,我们现在有一种方法可以在应用程序中更改主题:

app-changed-theme.png
更改主题后,我们的应用程序将 Context Hook 与 State Hook 结合使用

现在,我们有一个通过 Hook 使用的 context,也可以通过 Hook 进行更改!

示例代码

我们的博客应用程序中主题功能的示例代码可以在 Chapter05/chapter5_2 文件夹中找到。

只需运行 npm install 即可安装所有依赖项,运行 npm start 启动应用程序,然后在您的浏览器中访问 http://localhost:3000(如果它没有自动打开)。

使用全局状态的 Context

在学习如何使用 React Context 在我们的博客应用程序中实现主题之后,我们现在将使用 context 来避免手动传递状态并为我们的全局应用程序 statedispatch props。

定义 StateContext

我们首先在 src/context.js 文件中定义 context。

src/contexts.js 中,我们定义了 StateContext,它将存储 state 值和 dispatch 函数:

export const StateContext = React.createContext({
  state: {},
  dispatch: () => {}
})

我们将 state 值初始化为空对象,将 dispatch 函数初始化为空函数,当未定义 provider 时将使用该函数。

定义 Context Provider

现在,我们将在 src/App.js 文件中定义 context provider,该文件将从现有的 Reducer Hook 中获取值。

现在让我们定义全局状态的 context provider:

  1. src/App.js 中,通过调整现有的 import 语句来导入 StateContext
import { ThemeContext, StateContext } from './contexts'
  1. 然后,我们通过从 App 函数返回它来定义一个新的 context provider:
return (
  <StateContext.Provider value={{ state, dispatch }}>
    <ThemeContext.Provider value={theme}>
    ...
    </ThemeContext.Provider>
  </StateContext.Provider>
)

现在,我们的 context provider 为应用程序的其余部分提供了 state 对象和 dispatch 函数,我们可以继续使用 Context 值。

使用 StateContext

现在我们已经定义了 context 和 provider,我们可以在各种组件中使用 state 对象和 dispatch 函数。

我们首先删除我们在 src/App.js 中手动传递给组件的 props。删除以下代码段 第 4 ~ 7 行所有的 props:

<div style={{ padding: 8 }}>
  <Header text="React Hooks Blog" />
  <ChangeTheme theme={theme} setTheme={setTheme} />
  <UserBar user={user} dispatch={dispatch} />
  {user && <CreatePost user={user} posts={posts} dispatch={dispatch} />}
  <hr />
  <PostList posts={posts} />
</div>

由于我们使用 context,因此不再需要手动传递 props。现在,我们可以继续重构组件。

重构用户组件

首先,我们重构用户组件,然后我们继续讨论 post 组件。

现在让我们重构与用户相关的组件:

  1. 编辑 src/user/UserBar.js,并删除第 7 ~ 8 行代码的 prop,因为我们不再需要手动传递它们:
export default function UserBar({ user, dispatch }) {
  if (user) {
    return <Logout user={user} dispatch={dispatch} />
  } else {
    return (
      <React.Fragment>
        <Login dispatch={dispatch} />
        <Register dispatch={dispatch} />
      </React.Fragment>
    )
  }
}
  1. 然后,我们在 src/user/UserBar.js 中导入 useContext Hook 和 StateContext,以便能够判断用户是否已登录:
import React, { useContext } from 'react'
import { StateContext } from '../contexts'
  1. 现在,我们可以使用 Context Hook 从我们的 state 对象获取 user 状态:
export default function UserBar () {
  const { state } = useContext(StateContext)
  const { user } = state
  1. 同样,我们在 src/user/Login.js 中导入 useContextStateContext
import React, { useState, useContext } from 'react'
import { StateContext } from '../contexts'
  1. 然后,我们删除 dispatch prop,改用 Context Hook:
export default function Login () {
const { dispatch } = useContext(StateContext)
  1. 我们在 src/user/Register.js 组件中重复相同的过程:
import React, { useState, useContext } from 'react'
import { StateContext } from '../contexts'

export default function Register () {
  const { dispatch } = useContext(StateContext)
  1. src/user/Logout.js 组件中,我们执行相同的操作,但也从 state 对象获取 user 状态:
import React, { useContext } from 'react'
import { StateContext } from '../contexts'

export default function Logout () {
  const { state, dispatch } = useContext(StateContext)
  const { user } = state

我们的用户相关组件现在使用 context 而不是 props。让我们继续重构与文章相关的组件。

重构文章组件

现在,剩下要做的就是重构文章组件;那么我们的整个应用程序将使用 React Context 作为全局状态:

  1. 我们从 src/post/PostList.js 组件开始,我们在其中导入 useContextStateContext,删除 props,并使用 Context Hook:
import React, { useContext } from 'react'
import { StateContext } from '../contexts'
import Post from './Post'

export default function PostList () {
  const { state } = useContext(StateContext)
  const { posts } = state
  1. 我们对 CreatePost 组件执行相同的操作,这是我们需要重构的最后一个组件:
import React, { useState, useContext } from 'react'
import { StateContext } from '../contexts'

export default function createPost () {
  const { state, dispatch } = useContext(StateContext)
  const { user } = state

我们的应用程序的工作方式与以前相同,但现在我们使用全局状态的 context,这使我们的代码更加干净,并且避免了传递 props!

示例代码

我们的博客应用程序中全局状态 context 的示例代码可以在 Chapter05/chapter5_3 文件夹中找到。

只需运行 npm install 即可安装所有依赖项,运行 npm start 启动应用程序,然后在您的浏览器中访问 http://localhost:3000(如果它没有自动打开)。

总结

在本章中,我们首先了解了 React Context 作为在多个级别的 React 组件上传递 props 的替代方案。然后,我们了解了 Context provider 和 consumer,以及通过 Hook 定义 consumer 的新方法。接下来,我们学习了何时不该使用 context,以及何时应该使用控制反转。然后,我们使用在实践中学到的知识,在博客应用程序中实现主题。最后,我们在博客应用程序中使用了全局状态的 React Context。

在下一章中,我们将学习如何使用 React 和 Hook 从服务器请求数据。然后,我们将学习 React.memo 以防止不必要的组件重新渲染,以及 React Suspense 在需要时延迟加载组件。

问题

为了回顾我们在本章中学到的内容,请尝试回答以下问题:

  1. Context 可以避免哪些问题?
  2. Context 由哪两个部分组成?
  3. 是否需要定义这两个部分才能使用 context?
  4. 使用 Hook 而不是传统的 context consumer 有什么优势?
  5. 什么是 context 的替代方案,我们什么时候应该使用它?
  6. 我们如何实现动态变化的 context?
  7. 什么时候对状态使用 context 有意义?

延伸阅读

如果您对我们在本章中探讨的概念的更多信息感兴趣,请查看以下阅读材料:

2

评论 (0)

取消