• Stars
    star
    226
  • Rank 176,514 (Top 4 %)
  • Language
    JavaScript
  • Created almost 3 years ago
  • Updated almost 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Like useReducer, but runs in a worker.

useWorkerizedReducer

useWorkerizedReducer is like useReducer, but the reducer runs in a worker. This makes it possible to place long-running computations in the reducer without affecting the responsiveness of the app.

Example

// 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();
    }
  }
);

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

// 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>
    </>
  );
}

render(<App />, document.querySelector("main"));

Browser Support

useWorkerizedReducer works in all browsers. Firefox requires a polyfill.

(Currently, useWorkerizedReducer relies on WritableStream, which is available everywhere except Firefox. If you want to support Firefox, I recommend the web-streams-polyfill.)

Details

useWorkerizedReducer takes care of bringing the functionality of useReducer to a worker. It bridges the gap between worker and main thread by duplicating the reducer’s state to the main thread. The reducer manipulates the state object in the worker, and through ImmerJS only patches will be postMessage()’d to keep the main thread’s copy of the state up-to-date.

Due to the communication with a worker, useWorkerizedReducer is inherently asynchronous. In fact, part of the motivation was to enable long-running reducers, which means considerable time can pass between a dispatch() call and the subsequent state change. useWorkerizedReducer will fully finish processing an action before starting the next one, even if the reducer is async.

If a reducer is still running, the busy variable returned by useWorkerizedReducer will be set to true.

API

Exported methods

useWorkerizedReducer(worker, name, initialState): [State, DispatchFunc, isBusy];

isBusy will be true until the initialState has been successfully replicated to the worker. Afterwards, isBusy is true when there actions still being processed, false otherwise.

initWorkerizedReducer(name, reducerFunc, localState?);

name is the name of the reducer, which has to be identical to the name passed into useWorkerizedReducer. reducerFunc is a function of type (state, action, localState) => void | Promise<void>. It behaves the same as the reducer function you pass to the vanilla useReducer hook. In contrast to the reducer functions from the vanilla useReducer hook, it is important to manipulate the state object directly. ImmerJS is recording the operations performed on the object to generate a patch set. Creating copies of the object will not yield the desired effect. Since the modifications to state have to be transferred back to the main thread, the state object can only hold structured cloneable values.

localState is optional, and is a function of type (initialState) => LocalState. It will be called when a new reducer is being created and is expected to return a new local state instance. Local state will not be transferred to the main thread and therefore can hold references to values that are not structured cloneable, like functions or errors.

Convenience exports

For React:

import { ... } from "use-workerized-reducer/react";

For Preact:

import { ... } from "use-workerized-reducer/preact";

If, for some reason, you don’t want to use either of those, you can use the generic export. Note that useWorkerizedReducer takes 3 extra parameters, which have to be the useState, useEffect and useMemo hook in that order.

import { ... } from "use-workerized-reducer";

Apache-2.0

More Repositories

1

tinderforbananas.com

It’s like Tinder, but for 🍌
JavaScript
369
star
2

rollup-plugin-off-main-thread

Use Rollup with workers and ES6 modules today.
JavaScript
305
star
3

gobox

Something like busybox in pure Go
Go
238
star
4

underdash

Collection of JS snippets for collection manipulation
JavaScript
227
star
5

jsxx

Rust
169
star
6

observables-with-streams

A collection of observables built with streams.
TypeScript
133
star
7

ishoudinireadyyet.com

Tracker for Houdini APIs in different browsers
HTML
119
star
8

rollup-plugin-loadz0r

An ill-named rollup plugin that makes code splitting “just work”, even with workers.
JavaScript
98
star
9

jxl-art

Web app to make art using JPEG XL.
JavaScript
93
star
10

wasmphobia

Rust
91
star
11

rollup-plugin-assemblyscript

A Rollup plugin that allows you to import AssemblyScript files and compiles them on-the-fly.
JavaScript
74
star
12

httptools

Augmenting the basic net/http package with functionality found in web frameworks without breaking the original API.
Go
57
star
13

surma.dev

Personal Homepage
JavaScript
48
star
14

rollup-plugin-comlink

Use workers seamlessly with Rollup
JavaScript
38
star
15

s3put

Push a number of folders to a S3 bucket
Go
31
star
16

gopin

Tool-less version pinning for Go - surpassed by gopkg.in
Go
31
star
17

dof-tool

A web app to calculate your depth of field when doing photography.
JavaScript
30
star
18

silly-wat-linker

A tool that makes writing WebAssembly Text files easier.
Rust
28
star
19

streaming-dot

doT-based streaming templating engine for Node and the web
JavaScript
27
star
20

as-inliner

Inlines files into your AssemblyScript
JavaScript
26
star
21

rollup-plugin-workz0r

An ill-named rollup plugin that adds worker bundling support
JavaScript
26
star
22

bfwasm

A non-optimizing Brainf_ck to WebAssembly compiler
JavaScript
25
star
23

stacksignal

Make a go program print a stacktrace of all goroutines on SIGUSR1
Go
22
star
24

spreadsheet

TypeScript
18
star
25

rollup-plugin-wasm-esm

JavaScript
15
star
26

rollup-plugin-entrypoint-hashmanifest

A rollup plugin that generates a hash manifest for each entry point.
JavaScript
13
star
27

silly-alloc

A collection of very basic allocators. Written with WebAssembly in mind.
Rust
13
star
28

gocpio

A Go package for cpio archives
Go
13
star
29

webscribble

A simple, no-fluff web scratchpad.
JavaScript
7
star
30

miniqoi

A decoder for QOI in hand-written WebAssembly
WebAssembly
7
star
31

http2-push-detect

Lists HTTP/2 pushes when requesting an URL
JavaScript
7
star
32

rm2cal

A simple calendar/TODO list for Remarkable 2.
JavaScript
6
star
33

peasant

TypeScript
6
star
34

polymer-reddit-api

A simple element wrapping Reddit’s JSON API for my talk at the Polymer Summit 2015 in Amsterdam.
HTML
5
star
35

lurkk.it

TypeScript
4
star
36

platinum-god

JavaScript
3
star
37

emsettings

HTML
3
star
38

letterboxer

JavaScript
3
star
39

bikeshed-docker

Dockerfile for Bikeshed
3
star
40

javascript-pong

My very first JavaScript project from 2004
2
star
41

importalias

Go
2
star
42

osci

Emulator and tools for osci, a one-instruction set CPU derivatived from subleq
Rust
2
star
43

eatoutandstaysane

A web app to remove any mention of calories from food menu PDFs.
JavaScript
2
star
44

xmos-virtualport

Virtual ports to emulate arbitrary-sized GPIO ports on the XMOS architecture
C
1
star
45

shaderscribble

A simple, no-fluff shader scratchpad.
JavaScript
1
star
46

diplomaenhancer

Daemon to manipulate your local host file to block webpages which you consider distracting
JavaScript
1
star