import { Draft } from 'immer' import { useImmer } from 'use-immer' import { createContainer } from 'unstated-next' import { useRef, useEffect } from 'react' import { noop } from '@lib/helper' export function useObject (initialValue: T) { const [copy, rawSet] = useImmer(initialValue) function set> (key: K, value: Draft[K]): void function set> (data: Partial): void function set> (f: (draft: Draft) => void | T): void function set> (data: any, value?: Draft[K]): void { if (typeof data === 'string') { rawSet(draft => { const key = data as K const v = value draft[key] = v }) } else if (typeof data === 'function') { rawSet(data) } else if (typeof data === 'object') { rawSet((draft: Draft) => { const obj = data as Draft for (const key of Object.keys(obj)) { const k = key as keyof Draft draft[k] = obj[k] } }) } } return [copy, set] as [T, typeof set] } export function useInterval (callback: () => void, delay: number) { const savedCallback = useRef(noop) useEffect(() => savedCallback.current = callback, [callback]) useEffect( () => { const handler = () => savedCallback.current() if (delay !== null) { const id = setInterval(handler, delay) return () => clearInterval(id) } }, [delay] ) } type containerFn = (initialState?: State) => Value export function composeContainer, U extends { [key: string]: C }, K extends keyof U> (mapping: U) { function Global () { return Object.keys(mapping).reduce((obj, key) => { obj[key as K] = mapping[key]() return obj }, {} as { [K in keyof U]: T }) } const allContainer = createContainer(Global) return { Provider: allContainer.Provider, containers: Object.keys(mapping).reduce((obj, key) => { obj[key as K] = (() => allContainer.useContainer()[key]) as U[K] return obj }, {} as { [K in keyof U]: U[K] }) } }