UNPKG

use-sse

Version:

useSSE - use server-side effect

134 lines (133 loc) 4.73 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createServerContext = exports.createBroswerContext = exports.useSSE = exports.InternalContext = exports.DataContext = void 0; const react_1 = __importDefault(require("react")); exports.DataContext = react_1.default.createContext({}); exports.InternalContext = react_1.default.createContext({ requests: [], resolved: false, current: 0, }); const react_2 = require("react"); /** * * @param effect runction returning promise * @param dependencies list of dependencies like in useEffect */ function useSSE(effect, dependencies) { var _a, _b; const internalContext = react_2.useContext(exports.InternalContext); let callId = internalContext.current; internalContext.current++; const ctx = react_2.useContext(exports.DataContext); const [data, setData] = react_2.useState(((_a = ctx[callId]) === null || _a === void 0 ? void 0 : _a.data) || null); const [error, setError] = react_2.useState(((_b = ctx[callId]) === null || _b === void 0 ? void 0 : _b.error) || null); if (!internalContext.resolved) { let cancel = Function.prototype; const effectPr = new Promise((resolve) => { cancel = () => { if (!ctx[callId]) { ctx[callId] = { error: { messgae: "timeout" }, id: callId }; } resolve(callId); }; return effect() .then((res) => { return res; }) .then((res) => { ctx[callId] = { data: res }; resolve(callId); }) .catch((error) => { ctx[callId] = { error: error }; resolve(callId); }); }); internalContext.requests.push({ id: callId, promise: effectPr, cancel: cancel, }); } react_2.useEffect(() => { if (internalContext.resolved && !ctx[callId]) { effect() .then((res) => { setData(res); }) .catch((error) => { setError(error); }); } delete ctx[callId]; }, dependencies); return [data, error]; } exports.useSSE = useSSE; const createBroswerContext = (variableName = "_initialDataContext") => { const initial = window && window[variableName] ? window[variableName] : {}; let internalContextValue = { current: 0, resolved: true, requests: [], }; function BroswerDataContext(props) { return (react_1.default.createElement(exports.InternalContext.Provider, { value: internalContextValue }, react_1.default.createElement(exports.DataContext.Provider, { value: initial }, props.children))); } return BroswerDataContext; }; exports.createBroswerContext = createBroswerContext; const wait = (time) => { return new Promise((resolve, reject) => { setTimeout(() => { reject({ error: "timeout" }); }, time); }); }; const createServerContext = () => { let ctx = {}; let internalContextValue = { current: 0, resolved: false, requests: [], }; function ServerDataContext(props) { return (react_1.default.createElement(exports.InternalContext.Provider, { value: internalContextValue }, react_1.default.createElement(exports.DataContext.Provider, { value: ctx }, props.children))); } const resolveData = async (timeout) => { const effects = internalContextValue.requests.map((item) => item.promise); if (timeout) { const timeOutPr = wait(timeout); await Promise.all(internalContextValue.requests.map((effect, index) => { return Promise.race([effect.promise, timeOutPr]).catch(() => { return effect.cancel(); }); })); } else { await Promise.all(effects); } internalContextValue.resolved = true; internalContextValue.current = 0; return { data: ctx, toJSON: function () { return this.data; }, toHtml: function (variableName = "_initialDataContext") { return `<script>window.${variableName} = ${JSON.stringify(this)};</script>`; }, }; }; return { ServerDataContext, resolveData, }; }; exports.createServerContext = createServerContext;