React 状态管理:使用 Context 和 Reducer

React 是一个流行的前端开发框架,它拥有强大的、可重用的组件模型。然而,在你的应用程序中管理组件状态时,你可能会遇到令人沮丧的问题:传递状态和回调函数的深层嵌套层次结构。

为了解决这些问题,React 提供了一些机制使得状态管理和组件通信变得更加简单。在本文中,我们将讨论其中的两个机制:Context 和 Reducer。

Context

Context 是一种在组件之间共享数据的方式,它允许你通过组件树传递数据而不必手动地一级一级地将它们传递下去。这对于某些类型的属性(例如语言环境或主题)非常有用,并且它使得在组件中跨越多层级传递数据变得更加容易。

创建 Context

首先,让我们看看如何创建我们自己的 Context。我们不需要安装任何依赖项 - React 已经在其核心库中提供了它。

------ ----- ---- --------

----- --------- - -------------------------------------

我们可以通过向 createContext 方法传递一个默认值来创建 Context,这个默认值只有在没有 Provider 时才会生效。

提供值

接下来,我们需要创建一个上下文提供者 (Provider),并将值传递给它:

----- ---------- ------- --------------- -
  ----- - - ----- -------- ----- --

  -------- -
    ------ -
      ------------------- ------------------------
        ---------------------
      ---------------------
    --
  -
-

在上面的例子中,我们创建了一个 MyProvider 组件,在它的 render 方法中渲染 MyContext.Provider,并将 value 属性设置为 this.state.data。这个 value 将会被新的 Consumer 组件使用。

使用 Consumer

现在,我们可以在任何组件中使用 MyContext 中的数据了,只要它们被 MyProvider 的子组件所包裹。要使用 Context 数据,我们需要使用另一个 React 组件 Consumer

----- ---------- ------- --------------- -
  -------- -
    ------ -
      --------------------
        ------ -- -------- ----- --- --------------
      ---------------------
    --
  -
-

在这个例子中,我们创建了一个 MyConsumer 组件,并使用 Consumer 组件,来读取传递给上下文提供者的值。

示例应用

在这个示例应用中,我们将创建一个简单的事件计数器,这个计数器能够从任何组件中调用,并从 store 中获取数据。

首先,我们创建一个名为 Store 的文件,它将包含我们的数据以及操作数据的函数。

------ ----- ---- --------

------ ----- ----- - --------------------------

------ ----- ------------ - - ------ - --
------ ----- ------- - ------- ------- -- -
  ------ ------------- -
    ---- ------------
      ------ - ------ ----------- - - --
    --------
      ------ ------
  -
--

在这个例子中,我们创建了两个常量。第一个常量 Store 是我们的上下文,第二个常量 initialState 定义了我们 store 的默认状态,第三个常量 reducer 是用来更新 store 的纯函数。在这个简单的例子中,我们只有一个 increment 命令来增加计数器的数值。

接下来,我们将会创建一个名为 App 的组件,在这个组件中,我们将渲染给定的 children,并且提供一个 Store 上下文。我们还将定义 Store 的默认值,以防我们没有向 StoreProvider 传递值。

------ ----- ---- --------
------ - ------ ------------- ------- - ---- -----------

----- --- ------- --------------- -
  ----- - - ------ ------------- --------- ------ -- ------------------- -- -- ------ -------------------- ------- --- --

  -------- -
    ----- - ------ -------- - - -----------
    ------ --------------- -------- ------ -------- ------------------------------------------
  -
-

------ ------- ----

在这个例子中,我们创建了一个 App,它的 state 属性包含了整个 storedispatch 函数。在 render 函数中,我们通过将 storedispatch 传递给 Store,来提供 Store 上下文。

现在,我们可以在 App 中使用任何我们希望共享数据的组件。

比如 CounterButton 组件,这个组件渲染一个简单的 button,在被点击时调用 dispatch 函数:

------ ----- ---- --------
------ - ----- - ---- -----------

----- ------------- ------- --------------- -
  -------- -
    ------ -
      ----------------
        --- ------ -------- -- -- -
          ------- ----------- -- ---------- ----- ----------- ----
            ------- ------------- -----
          ---------
        --
      -----------------
    --
  -
-

------ ------- --------------

在这个例子中,我们使用 Consumer 组件来读取 store 中的值和 dispatch 函数,并使用 onClick 事件调用 dispatch

现在我们已经为我们的应用程序对象提供了上下文提供者和使用上下文提供者的组件,我们可以在所有需要使用数据的组件中使用他们了。

Reducer

在前面的示例中,我们通过在 dispatch 函数中使用 reducer 列表来更新状态。在这个简单的例子中,这是非常直观的。但是在更复杂的情况下,可能会需要进行更复杂的状态更改。在这种情况下,使用 React 的 Reducer 可以解决这个问题。

Action 类型

我们已经在之前的示例中使用了 action 对象来更改状态。在 Reducer 中,action 对象包含了一个 type 属性,它描述了我们应该执行的操作类型,以及可选的其他属性。

----- --------------- - - ----- ----------- --
----- --------------- - - ----- ------------ -------- -- --

在这个例子中,我们定义了两个不同的 actionincrementActiondecrementAction

Reducer 函数

Reducer 是一个纯函数,它接受当前状态和一个 action 对象并返回一个新的状态。

----- ------- - ------- ------- -- -
  ------ ------------- -
    ---- ------------
      ------ - --------- ------ ----------- - - --
    ---- ------------
      ------ - --------- ------ ----------- - -------------- --
    --------
      ------ ------
  -
--

在这个例子中,我们定义了一个 reducer 函数,它捕获类型为 'increment''decrement'action。在 "increment" 操作中,我们是用展开操作符 (...) 复制了当前状态,通过 count 属性增加数值。在 "decrement" 操作中使用了进一步一些操作,也通过 count 属性去减去 payload 属性作为减数的数值。

使用 Reducer

前面几节介绍了 Reducerdispatch 和我们上下文的设置。将它们结合在一起,按照 React 的官方文档中的建议来完成 Reducer 的使用。

我们使用 useReducer 来传入一个“Reducer 函数”,一个“初始状态”,以及一个“中间状态”的优化函数。然后就会返回一个 state 和 dispatch:

------ ------ - ----------- ------------- - ---- --------
------ - ------------- ------- - ---- ------------

------ ----- ----- - ----------------------------

------ ----- ------------- - -- -------- -- -- -
  ----- ------- --------- - ------------------- --------------
  ------ --------------- -------- ------ -------- -------------------------------
--

在这个代码示例中,我们使用了 useReducer api 初始化了 statedispatch。又用 value 属性来传入 context。

我们可以像前面一样,即在下游的 Consumer 中使用该 Context:

------ ----- ---- --------
------ - ----- - ---- ----------

------ ------- -------- --------------- -
  ----- - ------ -------- - - ------------------------
  ----- - ----- - - ------
  ------ ------- ----------- -- ---------- ----- ----------- ---------- -----------------
-

在本例子中,我们使用了 useContext 来获得 context 的值。一旦 statedispatch 发生更改,组件都将会重新渲染。我想提醒一下小伙们,千万不要忘了使用判断或者 useMemo 做性能优化。

当然,这仅仅只是 Reducer 的一个用例,它也可以用于处理更加复杂的状态更改逻辑。

结论

在本文中,我们介绍了使用 React 的 Context 和 Reducer 来管理状态的方式。我们创建了上下文提供者来共享数据,创建了使用上下文数据的消费者。在这些例子中,我们使用了 Reducers 作为一个状态管理器,注重解决了在更新多个操作的情况下,使用 Redux 和 Context 这样的状态管理库所需要的一些代码。

我希望此文章对您理解 React 的 Context 和 Reducer 有所帮助,它是一个更快,更干净,更简单的状态管理器。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/670c724666ef9cf37fb13fcb


猜你喜欢

  • Socket.io 与 Kafka 的实时数据传输方案

    实时数据传输是当今互联网应用中重要的一环,能够将数据快速地从一个应用程序传输到另一个应用程序。当然,要实现实时数据传输需要选择合适的技术方案。本文将介绍 Socket.io 和 Kafka,以及它们如...

    9 天前
  • RxJS 实战:如何处理重复的值?

    RxJS 是一个强大的响应式编程库,它提供了一种函数响应式编程的解决方案,并且在前端开发中被广泛应用。在使用 RxJS 时,我们经常会遇到一些重复的值,这时候必须对它们进行处理。

    9 天前
  • 在 ES6 和 ES7 中使用 Object.create() 方法来创建对象

    在 JavaScript 中,创建对象是一项基本任务。一般来说,可以使用字面量对象 ({}) 或构造函数 (例如 new Object()) 来创建对象。但是,这些方法都有其限制,而使用 Object...

    9 天前
  • RESTful API 中的 API 网关重构方法

    在现代的软件系统中,RESTful API 已经成为了不可或缺的部分。而在 RESTful API 的设计中,API 网关是非常重要的环节。API 网关可以处理请求的路由、限流、重试等逻辑,同时也可以...

    9 天前
  • 使用 Web Workers 优化 PWA 应用程序性能

    随着移动浏览器的不断发展,越来越多的网站和应用程序将它们的目光转向了 PWA(渐进式 Web 应用程序),以提供更好的离线体验和更快的加载速度。然而,PWA 应用程序的性能问题往往是一个挑战。

    9 天前
  • Chai 如何控制错误信息输出

    Chai 是一个流行的 JavaScript 断言库,用于编写测试以确保代码的正确性。在测试期间,可能会出现一些错误,这些错误可以以不同的方式呈现给开发人员。本文将介绍如何使用 Chai 库来控制错误...

    9 天前
  • Jest Snapshot:如何生成与使用

    Jest 是一个由 Facebook 开发的 JavaScript 测试框架,它支持多种测试类型,包括单元测试、集成测试和端到端测试等等。其中,快照测试是 Jest 最为流行的一种测试类型之一,它可以...

    9 天前
  • Serverless 架构和 Docker 容器之间的比较与区别

    Serverless 架构和 Docker 容器是当今流行的两种云计算技术,它们都可以帮助我们实现快速部署、可伸缩的应用程序。但是 Serverless 架构和 Docker 容器之间存在许多关键的区...

    9 天前
  • 在 Kubernetes 中发布自定义应用程序的完整指南

    如今,Kubernetes 在云计算和容器编排领域得到越来越广泛的应用。同时,随着前端技术的发展,前端应用程序也越来越复杂。如果你是一个前端开发者,你可以将你的自定义应用程序部署到 Kubernete...

    9 天前
  • 把 reselect 作为 redux 数据处理的最后一步

    在 Redux 应用程序中,使用 reselect 可以更高效地处理数据。reselect 可以将平深层次嵌套的多个数据连接为一个数据,并有助于组织以前使用链式调用嵌套映射器的代码。

    9 天前
  • 使用 ESLint 检查 JavaScript 中的潜在问题

    前言 随着前端技术的发展,JavaScript 已经成为 web 开发领域中最流行的编程语言之一。然而,当我们在编写 JavaScript 代码时,难免会出错。这些错误有可能是语法错误,也有可能是潜在...

    9 天前
  • 在 Fastify 中配置 Node.js 中间件

    Fastify 是一个快速、低开销且低级别的 Node.js Web 框架,拥有诸多特性和插件,使得在构建可靠的 Web 应用程序方面变得更加容易。本文将介绍如何在 Fastify 中配置 Node....

    9 天前
  • Koa2 中 bodyparser 解析 json 数据时出现的 bug 及解决方式

    在 Koa2 中,使用 bodyparser 中间件可以方便地解析请求体中的数据,其中包括解析 json 格式的数据。但是在实际开发中,你可能会遇到一些奇怪的 bug,比如无法正确解析 json 数据...

    9 天前
  • Mongoose 中使用生命周期 hooks 的详细指南

    Mongoose 是 Node.js 的一个 ORM 框架,用于简化与 MongoDB 数据库的交互。Mongoose 提供了许多有用的功能,其中包含生命周期 hooks。

    9 天前
  • 如何将 Tailwind CSS 应用于 WordPress 主题开发中

    在 WordPress 主题开发中,样式是非常重要的。而使用 Tailwind CSS 这样的 CSS 框架能够提高开发效率,同时也能帮助我们更好地管理我们的代码。

    9 天前
  • Apollo 和 Redis:如何缓存 GraphQL 查询

    GraphQL 是一种用于 API 开发的查询语言,它是前端领域的一个重要技术。然而,GraphQL 的查询可能会对服务器造成很大的负荷,导致响应变慢甚至崩溃。为了解决这个问题,我们可以使用缓存技术来...

    9 天前
  • 无障碍模式下的表单设计:方便用户与减少错误

    对于许多人来说,表单是他们与网站或应用程序进行交互的方式之一,因此,表单设计的重要性不言而喻。在我们设计表单时,考虑到无障碍用户的需求能够为他们提供方便而且减少错误,同时也提高了所有用户的用户体验。

    9 天前
  • Enzyme 测试中 React 组件的扩展性及可维护性

    Enzyme 测试中 React 组件的扩展性及可维护性 React 是目前最受欢迎的前端框架之一,但是随着 Web 应用程序规模的增大和功能的复杂性增加,维护和扩展现有代码变得越来越困难。

    9 天前
  • Socket.io 多服务器集群部署方式

    在现代 Web 应用程序中,即时通信被广泛使用。 Socket.io 是一个流行且强大的 Node.js 库,用于实现这种实时通信。但是,在大型应用程序中,单个服务器可能无法处理高流量和大量连接。

    9 天前
  • Material Design 教程之 Input Text Field 组件详解

    在许多 Web 应用程序中,文本输入字段是其中的核心组件之一。Material Design 提供了一套丰富的输入文本字段组件,它们被设计成能够很好地适应不同的输入场景,并且提供了强大的交互性和可访问...

    9 天前

相关推荐

    暂无文章