Webworker React Hook

September 21, 2024

React Hooks

Webworker React Hook

Thuta Sann

Thuta Sann

react custom hook to use webworker


Share This Snippet To :

Webworker React Hook

import { useCallback, useEffect, useRef, useState } from 'react' /** Worker Message Payload */ type MessagePayload<TResponse> = { /** message data */ data: TResponse | undefined /** error */ error?: Error | string } /** Webworker Config */ type WebWorkerConfig = { /** worker url */ url?: string /** webworker context */ worker?: Worker } /** Worker Container Ref */ type WorkerContainerRef = { /** worker */ worker?: Worker /** to determine to terminate the worker or not */ shouldTerminate?: boolean } /** * ### Webworker Hook * @param config - webworker config * @example * import FibonacciWorker from '../../../workers/fibonacci-worker?worker' * // define worker input type * type WorkerInput = { * input: number; * } * * // define worker response type * type WorkerResponse = { * result: number; * } * * // hook usage * * const [data, postData, error] = useWebWorker<WorkerInput, WorkerResponse>({ * worker: new FibonacciWorker(), * }) * * // handle action * const handleAction = (input: number) => { * postData({ input }) * } * * // response and error * console.log("Error >> ", error) * console.log("Result >> ", data) * * @version 1.0.0 * @author Thuta */ export function useWebWorker<TData, TResponse>(config: WebWorkerConfig) { // ✔ webworker config const { url, worker: workerContext } = config /** worker container */ const workerContainer = useRef<WorkerContainerRef>({}) // ✔ message payload state const [message, setMessage] = useState<MessagePayload<TResponse>>({ data: undefined, error: undefined, }) /** * onMessage Handler * @param payload - message payload */ const onMessage = useCallback((payload: MessageEvent<TResponse>): void => { const { data } = payload setMessage((prev) => { if (prev.data !== data) { return { data, error: undefined, } } return prev }) }, []) /** * onError Handler * @param errorEvent - error event */ const onError = useCallback((errorEvent: ErrorEvent): void => { setMessage({ data: undefined, error: errorEvent.message || new Error('Worker encountered an error'), }) }, []) /** * Post data to the WebWorker * @param data - message data */ const postData = useCallback((data: TData): void => { const { worker } = workerContainer.current if (!worker) { setMessage({ data: undefined, error: new Error('Worker not initialized'), }) } else { worker.postMessage(data) } }, []) /** * Create or retrieves a WebWorker */ const createWebWorker = (): Worker | undefined => { const { current } = workerContainer if (url) { current.worker = new Worker(url) current.shouldTerminate = true // should terminate since it was created internally } else if (workerContext) { current.worker = workerContext current.shouldTerminate = false // don't terminate external worker } return current.worker } /** * Set up the WebWorker and add event listeners */ const setupWebWorker = (): void => { const worker = createWebWorker() if (!worker) { setMessage({ data: undefined, error: 'Either Worker URL or Worker instance must be provided', }) return } worker.addEventListener('message', onMessage) worker.addEventListener('error', onError) } /** * Clean up WebWorker: remove event listeners and terminate if needed */ const terminateWebWorker = (): void => { const { worker, shouldTerminate } = workerContainer.current if (worker) { worker.removeEventListener('message', onMessage) worker.removeEventListener('error', onError) if (shouldTerminate) { worker.terminate() } workerContainer.current = {} } } // ✔ Setup WebWorker Effect useEffect(() => { setupWebWorker() return () => { terminateWebWorker() } // eslint-disable-next-line react-hooks/exhaustive-deps }, [url, workerContext, onMessage, onError]) return [message.data, postData, message.error] as const }

Cookie

I baked some cookies that you have to accept, if you want to enjoy my portfolio.
In order to gather information and make improvements, I should use some third-party cookies too, Can I?