【React】将 useReducer 应用于 Web Worker,擦出奇妙的火花

举报
Ocean2022 发表于 2022/05/21 11:24:00 2022/05/21
【摘要】 有这么一个场景,当加载一个网页时,它突然变得无响应,直到所有的资源完全加载完毕才响应。但是,当资源加载时,用户可能无法执行页面上的某些功能,比如单击、选择或拖动元素。这个时候你可能会想到使用 Web workers帮助我们解决这个问题。在本文中,我们将学习如何在 React 应用程序中使用web workers。我们还将学习通过 useWorkerizedReducer 在web worke...

有这么一个场景,当加载一个网页时,它突然变得无响应,直到所有的资源完全加载完毕才响应。但是,当资源加载时,用户可能无法执行页面上的某些功能,比如单击、选择或拖动元素。这个时候你可能会想到使用 Web workers帮助我们解决这个问题。
在本文中,我们将学习如何在 React 应用程序中使用web workers。我们还将学习通过 useWorkerizedReducer 在web worker 中使用 useReducer Hook。

web worker

web worker 是一个JavaScript脚本,它在后台运行,不会干扰其他脚本的执行。

因为JavaScript是单线程语言,它不能同时运行多个脚本,这对于运行大型计算脚本来说是一个问题。Web worker帮助在后台加载繁重的计算脚本,而不会影响页面的性能。

语法

const worker = new Worker(new URL("./worker.js", import.meta.url), {
 type: "module",
});

Worker 构造函数接受两个参数;第一个是 worker 文件名,第二个是worker 的类型。类型可以是 classic,或者是 module。如果未指定类型,则默认类型为 classic 。

在本文中,我们将使用module类型,因为 reducer 只能在组件中使用。要在 web worker 组件中使用 import 函数,我们必须将import.meta. URL 添加到 URL 构造函数中。

useReducer

useReducer是一个React Hook,用于存储和更新状态。它接受三个参数:reducer, initial state,作为最后一个参数,initial function,它是可选的:

const [state, dispatch] = useReducer(reducer, initialArg, init);

useReducer 返回一个包含当前 state 值的数组,以及一个 dispatch 函数,你可以向该 dispatch 函数提供要执行的操作。

dispatch 函数接受指定要执行的操作类型的对象。它本质上是将 action 的类型传递给 reducer 函数,而 reducer 函数用于更新 state。

reducer 函数

reducer 是一个接受两个参数的函数,当前 state 和 action 对象。它使用接收到的 action 来确定 state 的更改并返回新 state。

下面的代码演示了如何使用 reducer 函数来改变 state:

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};

   default:
      throw new Error();
  }
}

每当 reducer 函数被 action.type 触发时,它就会将新的 state 作为 reducer 函数内部的更改返回。

action 是一种对象类型,它指示 reducer 如何更改 state。它必须具有 type 属性。可以在条件语句中使用 action.type 来决定 state 如何更改。

为了让 reducer 函数在 web worker 中运行,我们必须使用useWorkerizedReducer。

useWorkerizedReducer

useWorkerizedReducer 类似于 useReducer,除了它允许 reducer 在 worker 中执行,还允许我们创建一个动态的 React 应用。

useWorkerizedReducer 允许在不影响应用程序响应的情况下将长时间运行的计算放置在 reducer 中。useWorkerizedReducer 负责向 worker 提供 useReducer 的功能。

通过将 reducer 的 state 复制到主线程,useWorkerizedReducer 在工作线程和主线程之间架起了桥梁。reducer 操作 worker 的 state 对象,使用 postMessage() 来保持复制主线程的当前状态。

实战:构建一个简单的计数器应用程序

为了学习如何在web worker中放置 Reducer,让我们创建一个简单的计数器程序,它将在当前 state 发生改变时返回。

首先,打开命令行,输入以下命令:

npx create-react-app my-app
cd my-app
npm start

在成功安装应用程序之后,我们需要将 useWorkerizedReducer 作为程序的依赖项来使用它。安装 “useWorkerizedReducer”,在终端中执行如下命令:

npm i use-workerized-reducer

现在我们已经成功安装了useWorkerizedReducer,让我们接着创建一个worker.js 文件。

创建 worker.js

因为我们在 worker.js 文件中使用了 reducer,所以我们将在 src 文件夹中创建 worker.js 文件: 单击“创建新文件”,将其命名为 worker.js,然后将其保存到 src 文件夹中,如下所示:

img

现在我们已经创建了 worker.js 文件,让我们在其中添加下面的 reducer 代码:

// worker.js
import { initWorkerizedReducer } from "use-workerized-reducer";

initWorkerizedReducer(
 "counter", //  reducer's name
 async (state, action) => {
   switch (action.type) {
     case "increment":
       state.counter += 1;
       break;
     case "decrement":
       state.counter -= 1;
       break;
     default:
       throw new Error();
   }
 }
);

在上面的代码中,我们从 use-workerizedreducer 中导入了initWorkerizedReducer。

initWorkerizedReducer() 接受两个参数:

  • 第一个是 reducer 的名称:counter。
  • 第二个是一个异步函数。

现在我们已经准备好了 worker.js 文件,我们需要从 use- workerizedreducer /react 中导入 useWorkerizedReducer ,这让我们可以从 worker 文件中调用 reducer 函数:

// main.js
import { render, h, Fragment } from "react";
import { useWorkerizedReducer } from "use-workerized-reducer/react";

const worker = new Worker(new URL("./worker.js", import.meta.url), {
 type: "module",
});

function App() {
 // 一个 worker 可以包含多个不同名的 reducer

 const [state, dispatch, busy] = useWorkerizedReducer(
   worker,
   "counter", // Reducer name
   { counter: 0 } // Initial state
 );

 return (
   <>
     Count: {state.counter}
     <button disabled={busy} onClick={() => dispatch({ type: "decrement" })}>
       -
     </button>
     <button disabled={busy} onClick={() => dispatch({ type: "increment" })}>
       +
     </button>
   </>
 );
}

export default App;

useWorkerizedReducer 函数接受三个参数并返回单个值:

  • 当前state是第一个参数;
  • action 是第二个参数;
  • 初始状态是第三个参数。

处理的数据是 state,dispatch 函数执行传递给 reducer 函数的action。

Busy将一直为 true,直到 worker 的初始状态 counter 成功复制到 worker。在此之后,如果 actions 仍在处理中,则 Busy 返回 true,否则返回 false。

reducer 根据 action 类型改变状态。action 类型 increment, decrement和reset都是在 dispatch 时更新 state 的 action 类型。

初始状态为{counter: 0}。当递增操作类型被 dispatch 时,我们简单地设置 count {state.Count + 1}。

结尾

在这篇文章中,我们简要介绍了 web worker 和 useReducer,以及如何构造和添加 web worker 文件到 React 应用程序中。

我们还讨论了useWorkerizedReducer,它为 web worker 带来了useReducer 的功能。最后,我们介绍了在useWorkerizedReducer的帮助下在 web worker中使用 reducer。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。