import {useCallback, useContext, useEffect, useState} from 'react'; import {StreamsContext} from "./streamsContext"; import {ApplicationContext} from "context"; import {Emitter, Stream} from "lstream"; import produce from "immer"; export function useStream(getStream: Stream | ((ctx: ApplicationContext) => Stream)) : T { const basicStreams = useContext(StreamsContext); const [state, setState] = useState<{data: T}>(); const stream: Emitter = resolveStream(getStream, basicStreams); if (!stream) { console.log(getStream); throw "no stream ^"; } useEffect(() => stream.attach(data => setState({data})), [stream]); // @ts-ignore return state ? state.data : (stream.value !== undefined ? stream.value : null); } export function useStreamWithUpdater(getStream: (ctx: ApplicationContext) => Emitter) : [T, (val: T|((T) => T)) => void] { const data = useStream(getStream); const basicStreams = useContext(StreamsContext); const stream = resolveStream(getStream, basicStreams); const updater = useCallback((val) => { if (typeof val === 'function') { val = val(data) } stream.next(val) }, [data, stream]); return [data, updater]; } export type Patcher = (draft: T) => void; export function useStreamWithPatcher(getStream: (ctx: ApplicationContext) => Emitter) : [T, (patcher: Patcher) => void] { const data = useStream(getStream); const basicStreams = useContext(StreamsContext); const stream: Emitter = resolveStream(getStream, basicStreams); const patch = (patcher: Patcher) => { const newData: T = produce(data, (draft:T) => { patcher(draft) }) stream.next(newData); } return [data, patch]; } function resolveStream(getStream, basicStreams): Emitter { return typeof getStream === 'function' ? getStream(basicStreams) : getStream }