”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 在 React Hooks 应用程序中利用 Web Worker 进行后台处理。

在 React Hooks 应用程序中利用 Web Worker 进行后台处理。

发布于2024-08-28
浏览:138

1.0 Introduction

Web Workers in React are functions that allow concurrent running of multiple threads in a React application.It enables some of the threads to run in the background, to exclude it from running as part of the main thread.

Take for example, you have an application where maybe you want to perform a complex calculation, large data fetching from an API or implementing a background notification, without altering the normal funtionality of the currently running main thread. This can be achieved by implementing React Web Hooks that ensure that the User Interface does not freeze while all these processes run in a React app.

In this guide, we will create a sample react project that implements web workers in custom react hooks to perform an exponential calculation.

Steps

Step 1: Create the React App

Create a react application.

npx create-vite myproject -- --template react

I prefer using vite to create a react app since it has a faster run time compared to create-react-app .
Here we use react as the template from vite.

Select React as your template

select JavaScript:

Select Variant as JavaScript

Utilizing Web Workers for Background Processing in React Hooks Applications.

open the project on an editor. (I'll use Vs code for this project)

code .

Step 2: Scaffolding our project.

Inside the src directory, create another directory hooks/useWebWorkers.
Inside this folder, create an index.js file that will hold our web worker as shown below:

Utilizing Web Workers for Background Processing in React Hooks Applications.

Step 3: Creating our web worker

Inside our /hooks/useWebWorker/index.js, we create a custom hook, that creates our web worker

Create a useWebWorker custom hook that takes workerFunction and inputData as parameters.

const useWebWorker =(workerFunction,inputData)=>{

}
export default useWebWorker;

Initialize states for our result,error and status of our web worker using useState hook.

import {useState} from 'react'
const useWebWorker =(workerFunction,inputData)=>{
const [result,setResult] = useState(null);
const [error,setError] = useState(null);
const [loading,setLoading] = useState(false);

}
export default useWebWorker;

i) result stores the result of our web worker. Initially set to null.

ii)error keeps track of the error that may occur in the web worker.Initially set to null.

iii) loading gives state of our web worker whether it's processing data or not.Initially set to false.

Initialize a useEffect to hold our web worker.

import {useState,useEffect} from 'react'
const useWebWorker =(workerFunction,inputData)=>{
const [result,setResult] = useState(null);
const [error,setError] = useState(null);
const [loading,setLoading] = useState(false);

useEffect(()=>{

},[inputData])

}
export default useWebWorker;

The useEffect hook runs whenever inputData changes, because it has been set as a delimiter,
When the inputData is null or undefined, the hook exits early.

if(!inputData)return;

Ensure that all the states are correctly reset

    setLoading(true);
    setError(null);
    setResult(null);

Create a web worker blob

    const blob = new Blob(
      [
        `
          self.onmessage = function(event) {
            (${workerFunction.toString()})(event);
          };
        `,
      ],
      { type: "application/javascript" }
    );

Converts workerFunction to a string and includes it in a Blob object.This Blob represents the JavaScript code that will run in the Web Worker.

Create a Worker that generates a URL for the Blob and creates a new Web Worker using this URL:

    const workerScriptUrl = URL.createObjectURL(blob);
    const worker = new Worker(workerScriptUrl);

Set up an event handler for the message emitted by the worker.

worker.onmessage(event){

}

when the web worker sends a message to the main thread (using postMessage), the event handler is triggered.
event.data contains either valid result or error in the web worker. We handle rendering of either the error or valid results inside the if-else statements.

In case of an error, we set the error to event.data.error inside setError().
if valid results are returned, we pass the result to event.data inside the setResult()

    worker.onmessage = (event) => {
      console.log("Worker result:", event.data);
      if (event.data.error) {
        setError(event.data.error);
      } else {
        setResult(event.data);
      }
      setLoading(false);
    };

Sets loading to false when done.

Handle Web worker errors:

We use worker.onerror(event){

}
We pass event as a parameter,update the error to event.message and update loading state to false.

    worker.onerror = (event) => {
      console.error("Worker error:", event.message);
      setError(event.message);
      setLoading(false);
    };

We now send the inputData to the web worker

worker.postMessage(inputData);

We terminate the Web Worker and revoke the Blob URL when the component unmounts or inputData or workerFunction changes:

    return () => {
      worker.terminate();
      URL.revokeObjectURL(workerScriptUrl);
    };
  }, [inputData, workerFunction]);

We finally return the state of the web worker by returning result,error and loading states:

return {result,error,loading}

Export the useWebWorker:

export default useWebWorker;

Below is the complete code for hooks/useWebWorker/index.js:

import { useState, useEffect } from "react";

const useWebWorker = (workerFunction, inputData) => {
  const [result, setResult] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (!inputData) return;

    setLoading(true);
    setError(null);
    setResult(null);

    const blob = new Blob(
      [
        `
          self.onmessage = function(event) {
            (${workerFunction})(event);
          };
        `,
      ],
      { type: "application/javascript" }
    );

    const workerScriptUrl = URL.createObjectURL(blob);
    const worker = new Worker(workerScriptUrl);

    worker.onmessage = (event) => {
      console.log("Worker result:", event.data);
      setResult(event.data);
      setLoading(false);
    };

    worker.onerror = (event) => {
      console.error("Worker error:", event.message);
      setError(event.message);
      setLoading(false);
    };

    console.log("Posting message to worker:", inputData);
    worker.postMessage(inputData);

    return () => {
      worker.terminate();
      URL.revokeObjectURL(workerScriptUrl);
    };
  }, [inputData, workerFunction]);

  return { result, error, loading };
};

export default useWebWorker;

Step 4: Editing our App.jsx

In our App.jsx, let's define a worker function that will be executed by our web worker:

const workerFunction = (e) => {
  const { base, exponent } = e.data;
  console.log("Worker function received data:", base, exponent);

  let result = 1;
  for (let i = 0; i 



e.data contains data from the web worker.

The workerFunction:
Logs the received data (base and exponent).
Computes the power of base raised to exponent.
Sends the result back to the main thread using self.postMessage(result).

Let's now define our App functional component inside our App.jsx:

const App = () => {
  const [base, setBase] = useState("");
  const [exponent, setExponent] = useState("");
  const [inputData, setInputData] = useState(null);
  const { result, error, loading } = useWebWorker(workerFunction, inputData);

base: Stores the base number input.
exponent: Stores the exponent number input.
inputData: Stores the data to be sent to the worker.
Custom Hook Usage: useWebWorker is used to create a Web Worker and manage its state.

  const handleBaseChange = (e) => setBase(e.target.value);
  const handleExponentChange = (e) => setExponent(e.target.value);

handleBaseChange: Updates base state when the input value changes.
handleExponentChange: Updates exponent state when the input value changes

  const handleCalculate = () => {
    setInputData({ base: Number(base), exponent: Number(exponent) });
  };

handleCalculate Function: Converts base and exponent to numbers and sets them as inputData for the Web Worker.

  return (
    

Exponential Calculation with Web Worker

{loading &&
Loading...
} {error &&
Error: {error}
} {!loading && !error && result !== null &&
Result: {result}
}
); };

JSX Layout:
Displays a title and input fields for base and exponent.
A button triggers the handleCalculate function.
Conditionally renders loading, error, or result messages based on the state.

Below is the complete App.jsx code:

import { useState } from "react";
import useWebWorker from "./hooks/useWebWorker";
import "./App.css";

const workerFunction = (e) => {
  const { base, exponent } = e.data;
  console.log("Worker function received data:", base, exponent);

  let result = 1;
  for (let i = 0; i  {
  const [base, setBase] = useState("");
  const [exponent, setExponent] = useState("");
  const [inputData, setInputData] = useState(null);
  const { result, error, loading } = useWebWorker(workerFunction, inputData);

  const handleBaseChange = (e) => setBase(e.target.value);
  const handleExponentChange = (e) => setExponent(e.target.value);

  const handleCalculate = () => {
    setInputData({ base: Number(base), exponent: Number(exponent) });
  };

  return (
    

Exponential Calculation with Web Worker

{loading &&
Loading...
} {error &&
Error: {error}
} {!loading && !error && result !== null &&
Result: {result}
}
); }; export default App;

We can now use npm run dev to view our project.
Below is a live preview of our project:
Web Workers Project Implementation

Conclusion

Implementing Web Workers in your React applications can significantly enhance performance, especially when dealing with CPU-intensive tasks. By offloading such tasks to background threads, you ensure that your app remains responsive and provides a smooth user experience.

In our example, we've seen how straightforward it can be to set up and use Web Workers in a React environment. From dynamically creating a worker using a custom hook to managing the communication between the main thread and the worker, every step is designed to be both efficient and easy to integrate.

This approach not only helps in maintaining a responsive UI but also makes your app more robust and user-friendly. Whether it's for complex calculations, data processing, or any other heavy lifting, Web Workers can be your go-to solution for multitasking in modern web applications.

Remember, the key to a great user experience is not just about what your app does but how it feels while doing it. By implementing Web Workers, you can ensure that your app feels snappy and responsive, keeping your users happy and engaged. So, go ahead and explore the power of Web Workers in your next React project – your users will thank you for it!

版本声明 本文转载于:https://dev.to/alekiie/utilizing-web-workers-for-background-processing-in-react-hooks-applications-127d?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 跨域场景下CORS何时使用预检请求?
    跨域场景下CORS何时使用预检请求?
    CORS:了解跨域请求的“预检”请求跨域资源共享 (CORS) 在制作 HTTP 时提出了挑战跨域请求。为了解决这些限制,引入了预检请求作为解决方法。预检请求说明预检请求是先于实际请求(例如 GET 或 POST)的 OPTIONS 请求)并用于与服务器协商请求的权限。这些请求包括两个附加标头:Ac...
    编程 发布于2024-11-05
  • 如何使用 PHP 的 glob() 函数按扩展名过滤文件?
    如何使用 PHP 的 glob() 函数按扩展名过滤文件?
    在 PHP 中按扩展名过滤文件使用目录时,通常需要根据扩展名检索特定文件。 PHP 提供了一种使用 glob() 函数来完成此任务的有效方法。要按扩展名过滤文件,请使用语法:$files = glob('/path/to/directory/*.extension');例如,要检索目录 /path/...
    编程 发布于2024-11-05
  • 理解 JavaScript 中的 Promise 和 Promise Chaining
    理解 JavaScript 中的 Promise 和 Promise Chaining
    什么是承诺? JavaScript 中的 Promise 就像你对未来做某事的“承诺”。它是一个对象,表示异步任务的最终完成(或失败)及其结果值。简而言之,Promise 充当尚不可用但将来可用的值的占位符。 承诺国家 Promise 可以存在于以下三种状态之一: ...
    编程 发布于2024-11-05
  • 安全分配
    安全分配
    今天,关于 JavaScript 中安全赋值运算符 (?=) 的新提案引起了热烈讨论。我喜欢 JavaScript 随着时间的推移而不断改进,但这也是我最近在一些情况下遇到的问题。我应该将快速示例实现作为函数,对吧? 如果您还没有阅读该提案,以下是其建议: const [error, value] ...
    编程 发布于2024-11-05
  • 创建队列接口
    创建队列接口
    创建字符队列的接口。 需要开发的三个实现: 固定大小的线性队列。 循环队列(复用数组空间)。 动态队列(根据需要增长)。 1 创建一个名为 ICharQ.java 的文件 // 字符队列接口。 公共接口 ICharQ { // 向队列中插入一个字符。 void put(char ch); ...
    编程 发布于2024-11-05
  • Pip 的可编辑模式何时对本地 Python 包开发有用?
    Pip 的可编辑模式何时对本地 Python 包开发有用?
    使用 Pip 在 Python 中利用可编辑模式进行本地包开发在 Python 的包管理生态系统中,Pip 拥有“-e”(或'--editable') 特定场景的选项。什么时候使用这个选项比较有利?答案在于可编辑模式的实现,官方文档中有详细说明:“从本地以可编辑模式安装项目(即 se...
    编程 发布于2024-11-05
  • 当您在浏览器中输入 URL 时会发生什么?
    当您在浏览器中输入 URL 时会发生什么?
    您是否想知道当您在浏览器中输入 URL 并按 Enter 键时幕后会发生什么?该过程比您想象的更加复杂,涉及多个步骤,这些步骤无缝地协同工作以提供您请求的网页。在本文中,我们将探讨从输入 URL 到查看完全加载的网页的整个过程,阐明使这一切成为可能的技术和协议。 第 1 步:输入 U...
    编程 发布于2024-11-05
  • 如何有效管理大量小HashMap对象的“OutOfMemoryError:超出GC开销限制”?
    如何有效管理大量小HashMap对象的“OutOfMemoryError:超出GC开销限制”?
    OutOfMemoryError: Handling Garbage Collection Overhead在Java中,当过多时会出现“java.lang.OutOfMemoryError: GC Overhead limit allowed”错误根据 Sun 的文档,时间花费在垃圾收集上。要解决...
    编程 发布于2024-11-05
  • 为什么在 Python 列表初始化中使用 [[]] * n 时列表会链接在一起?
    为什么在 Python 列表初始化中使用 [[]] * n 时列表会链接在一起?
    使用 [[]] * n 进行列表初始化时的列表链接问题使用 [[]] 初始化列表列表时 n,程序员经常会遇到一个意想不到的问题,即列表似乎链接在一起。出现这种情况是因为 [x]n 语法创建对同一基础列表对象的多个引用,而不是创建不同的列表实例。为了说明该问题,请考虑以下代码:x = [[]] * ...
    编程 发布于2024-11-05
  • Python 变得简单:从初学者到高级 |博客
    Python 变得简单:从初学者到高级 |博客
    Python Course Code Examples This is a Documentation of the python code i used and created , for learning python. Its easy to understand and L...
    编程 发布于2024-11-05
  • 简化 TypeScript 中的类型缩小和防护
    简化 TypeScript 中的类型缩小和防护
    Introduction to Narrowing Concept Typescript documentation explains this topic really well. I am not going to copy and paste the same descrip...
    编程 发布于2024-11-05
  • 何时应该使用 session_unset() 而不是 session_destroy() ,反之亦然?
    何时应该使用 session_unset() 而不是 session_destroy() ,反之亦然?
    理解 PHP 中 session_unset() 和 session_destroy() 的区别PHP 函数 session_unset() 和 session_destroy() 有不同的用途管理会话数据。尽管它们在清除会话变量方面有明显相似之处,但它们具有不同的效果。session_unset(...
    编程 发布于2024-11-05
  • 如何选择在 C++ 中解析 INI 文件的最佳方法?
    如何选择在 C++ 中解析 INI 文件的最佳方法?
    在 C 中解析 INI 文件:各种方法指南在 C 中处理初始化 (INI) 文件时,开发人员经常遇到有效解析这些文件以提取所需信息的挑战。本文探讨了用 C 解析 INI 文件的不同方法,讨论了它们的优点和注意事项。本机 Windows API 函数一种方法是利用 Windows API 函数INI ...
    编程 发布于2024-11-05
  • 代码日:重新聚焦
    代码日:重新聚焦
    2024 年 8 月 19 日星期一 今天是我 100 天编程之旅的一半! ?除了记录我的进步之外,我还喜欢分享学习技巧。我最喜欢的新方法之一是番茄工作法,它需要专注于一项任务 25 分钟,然后休息 5 分钟。四个周期后,您会休息更长的时间。这有助于保持注意力并防止倦怠。 我尝试过 App Stor...
    编程 发布于2024-11-05
  • 为什么我在 Visual Studio 2015 中收到编译器错误 C2280“尝试引用已删除的函数”?
    为什么我在 Visual Studio 2015 中收到编译器错误 C2280“尝试引用已删除的函数”?
    Visual Studio 2015 中编译器错误 C2280“尝试引用已删除的函数”Visual Studio 2015 编译器与其 2013 的前身不同,自动为定义移动构造函数或移动赋值运算符的类生成删除的复制构造函数。 C 标准强制执行此行为,以防止在首选移动的情况下发生意外复制。在您的代码片...
    编程 发布于2024-11-05

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3