useReducer Hooks into web workers
When a web page loads, it becomes unresponsive until all of the resources load completely. When the resource is loading, users may be unable to perform certain functions on the page, like clicking, selecting, or dragging elements. web workers help us to solve this problem, making our application dynamic so it loads faster.
In this tutorial, we’ll learn how to use web workers in a React application. We’ll also learn how to use the useReducer Hook within a web worker with useWorkerizedReducer. Let’s get started!
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
useReducer Hook?reducer functionuseWorkerizedReducerworker.jsA web worker is a JavaScript script that runs in the background without interfering with the execution of other scripts.
Because JavaScript is a single-threaded language, it cannot run several scripts at the same time, which is an issue for running large computation scripts. web workers help load heavy computation scripts in the background without affecting the performance of the page.
const worker = new Worker(new URL("./worker.js", import.meta.url), {
type: "module",
});
The worker constructor accepts two parameters; the first is the worker file name, and the second is the worker type. The type worker can either be classic or module. If the type is not specified, the default type will be classic.
In this tutorial, we’ll use the module type because the reducer can only be used inside a component. To use the import function inside the web worker component, we must add the import.meta.url to the URL constructor. We’ll demonstrate this later in the tutorial.
useReducer Hook?useReducer is an additional React Hook that is used to store and update states. It accepts three parameters, reducer, initial state, and as the last parameter, initial function, which is optional:
const [state, dispatch] = useReducer(reducer, initialArg, init);
useReducer returns an array containing the current state value, as well as a dispatch function to which you can supply an action to be executed.
The dispatch function accepts an object that specifies the type of action to be executed. It essentially communicates the type of action to the reducer function, which, of course, updates the state.
reducer functionA reducer is a function that accepts two parameters, the current state and an action object. It uses the action it receives to determine the change in state and return the new state.
The code below demonstrates how reducer function can be use to change 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();
}
}
Whenever the reducer function is triggered by the action type, it returns the new state as a change inside the reducer function.
An action is a type of object that instructs the reducer on how to change the state. It must have a type property. The action type can be used in a conditional statement to make decisions on how the state changes, as shown in the code block above.
To make the reducer run in a web worker, we have to use useWorkerizedReducer.
useWorkerizedReduceruseWorkerizedReducer is similar to useReducer, except it allows the reducer to execute in a worker, allowing us to create a dynamic React application.
useWorkerizedReducer also allows long-running computations to be placed in the reducer without affecting the application’s responsiveness. useWorkerizedReducer is responsible for providing useReducer‘s capabilities to a worker.
By replicating the reducer’s state to the main thread, useWorkerizedReducer bridges the gap between the worker and the main thread. The reducer manipulates the worker’s state object, and the only patch will be postMessage() through Immer to keep the main thread’s copy of the state current.
To learn how to place Reducer in a web worker, let’s create a simple counter program that will return whenever the current state is changed. To create the new program, open the command line and enter the following commands:
npx create-react-app my-app cd my-app npm start
After the application has been installed successfully, we need to install useWorkerizedReducer as a dependency on our program to use it. To install useWorkerizedReducer, run the following command in the terminal:
npm i use-workerized-reducer
Now that we’ve successfully installed useWorkerizedReducer, let’s go ahead and create a worker.js module file.
worker.jsSince we’re using reducer in the worker.js file, we’ll create the worker.js file inside the src folder.To create the worker.js file, click on create a new file, name the file worker.js, then save it inside the src folder, as shown below:

Now that we’ve created the worker.js file, let’s add the reducer code below inside it:
// worker.js
import { initWorkerizedReducer } from "use-workerized-reducer";
initWorkerizedReducer(
"counter", // Name of the reducer
async (state, action) => {
// Reducers can be async!
// Manipulate `state` directly. ImmerJS will take
// care of maintaining referential equality.
switch (action.type) {
case "increment":
state.counter += 1;
break;
case "decrement":
state.counter -= 1;
break;
default:
throw new Error();
}
}
);
From the code above, we import initWorkerizedReducer from use-workerized-reducer, which is made available from the useWorkerizedReducer dependency.
The initWorkerizedReducer() takes two parameters; the first is the reducer name(counter), and async function is the second.
Now that we have the worker.js file ready, we need to import useWorkerizedReducer from use-workerized-reducer/react, which gives us access to call the reducer function from the worker file:
// main.js
import { render, h, Fragment } from "react";
import { useWorkerizedReducer } from "use-workerized-reducer/react";
// Spin up the worker running the reducers.
const worker = new Worker(new URL("./worker.js", import.meta.url), {
type: "module",
});
function App() {
// A worker can contain multiple reducers, each with a unique name.
// `busy` is true if any action is still being processed.
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;
The useWorkerizedReducer function takes three parameters and returns a single value. The current state is the first parameter, the action is the second, and initial state is the third parameter. The data we’re working with is the state. A dispatch function executes an action that is passed to the reducer function.
Busy will remain true until the worker’s initial state counter has been successfully replicated to the worker. After that, Busy returns true if actions are still being processed and false otherwise.
The reducer changes the state based on the action type. The action types increment, decrement, and reset are all action types that update the app’s state when dispatched.
The initial state is { counter: 0 }. When the increment action type is dispatched, we simply set count {state.count + 1} to increment the state.
To start the application, enter the command below in the command line:
npm start
In this article, we covered a quick overview of web workers and useReducer as an additional Hook in React, as well as how to construct and add web worker files to your React applications.
We also discussed useWorkerizedReducer, which brings the functionality of useReducer to a web worker. Finally, we covered using reducer inside the web worker with the help of useWorkerizedReducer.
I hope you enjoyed this article! Be sure to leave a comment if you have any questions. Happy coding!
Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not
server-side
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
// Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>

CSS text-wrap: balance vs. text-wrap: prettyCompare and contrast two CSS components, text-wrap: balance and text-wrap: pretty, and discuss their benefits for better UX.

Remix 3 ditches React for a Preact fork and a “Web-First” model. Here’s what it means for React developers — and why it’s controversial.

A quick guide to agentic AI. Compare Autogen and Crew AI to build autonomous, tool-using multi-agent systems.

Compare the top AI development tools and models of November 2025. View updated rankings, feature breakdowns, and find the best fit for you.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now