UNPKG

@supunlakmal/hooks

Version:

A collection of reusable React hooks

82 lines 3.12 kB
import { useCallback, useEffect, useRef, useState } from 'react'; /** * `useWebWorker` is a custom React hook that allows you to run a function in a web worker, * to avoid blocking the main thread. * * @param workerFunction - The function to run in the web worker. * @returns An object containing the result, error, loading state, and functions to execute or terminate the worker. */ export const useWebWorker = (workerFunction) => { const [workerState, setWorkerState] = useState({ result: null, error: null, isLoading: false, }); const workerRef = useRef(null); const workerFunctionRef = useRef(workerFunction); useEffect(() => { workerFunctionRef.current = workerFunction; }, [workerFunction]); const executeWorker = useCallback((...args) => { setWorkerState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: true, error: null }))); const workerCode = ` onmessage = (event) => { try { const workerFunction = (${workerFunctionRef.current.toString()}); const result = workerFunction(...event.data); postMessage({ type: 'success', result }); } catch (error) { postMessage({ type: 'error', error: error.message }); } }; `; const blob = new Blob([workerCode], { type: 'text/javascript' }); const url = URL.createObjectURL(blob); workerRef.current = new Worker(url); workerRef.current.onmessage = (event) => { var _a; if (event.data.type === 'success') { setWorkerState({ result: event.data.result, error: null, isLoading: false, }); } else if (event.data.type === 'error') { setWorkerState({ result: null, error: new Error(event.data.error), isLoading: false, }); } URL.revokeObjectURL(url); (_a = workerRef.current) === null || _a === void 0 ? void 0 : _a.terminate(); }; workerRef.current.onerror = (error) => { var _a; setWorkerState({ result: null, error: new Error(error.message), isLoading: false, }); URL.revokeObjectURL(url); (_a = workerRef.current) === null || _a === void 0 ? void 0 : _a.terminate(); }; workerRef.current.postMessage(args); }, []); const terminateWorker = useCallback(() => { if (workerRef.current) { workerRef.current.terminate(); workerRef.current = null; setWorkerState((prev) => (Object.assign(Object.assign({}, prev), { isLoading: false }))); } }, []); useEffect(() => { return () => { terminateWorker(); }; }, [terminateWorker]); return Object.assign(Object.assign({}, workerState), { executeWorker, terminateWorker }); }; //# sourceMappingURL=useWebWorker.js.map