import { useEffect, useReducer, useState, type Dispatch, type Reducer, type StateUpdater } from "preact/hooks"; import { loadObject, saveObject } from "@common/storage"; export const useRemoteState = (key: string, initialValue: T) => { const storedKey = `useRemoteState.${key}`; const [value, setValue] = useState(initialValue); useEffect(() => { loadObject(storedKey, initialValue).then(setValue); }, [storedKey]); useEffect(() => { saveObject(storedKey, value); }, [storedKey, value]); return [value, setValue] as [T, Dispatch>]; }; const hydrate = Symbol('hydrate'); type HydrateAction = { type: typeof hydrate; payload: T }; const isHydrateAction = (action: unknown): action is HydrateAction => typeof action === 'object' && action !== null && 'type' in action && action.type === hydrate; const wrapReducer = (reducer: Reducer): Reducer> => (state, action) => { if (isHydrateAction(action)) { return action.payload; } return reducer(state, action); }; export const useRemoteReducer = (key: string, reducer: Reducer, initialValue: T) => { const storedKey = `useRemoteReducer.${key}`; const [state, dispatch] = useReducer(wrapReducer(reducer), initialValue); useEffect(() => { loadObject(storedKey, initialValue).then((loaded) => { dispatch({ type: hydrate, payload: loaded }); }); }, [storedKey]); useEffect(() => { saveObject(storedKey, state); }, [storedKey, state]); return [state, dispatch] as [T, Dispatch]; };