import { useState, useEffect } from "react"; import type { UndoStack, State } from ".."; /** * A simple hook that returns a function to trigger a rerender for the current component. */ const useForceUpdate = () => { const [fakeState, setFakeState] = useState(false); return () => { setFakeState(!fakeState); }; }; /** * A hook to update the component whenever the stack changes. * Useful for a stack/history viewer. * * @param stack The stack to watch. * @returns The stack passed as parameter. * * @example * ```ts * const StackDisplay = () => { * useUndoStack(stack); * return stack * .getStack() * .map(entry => entry.name) * .map(entry =>
{entry}
); * } * ``` */ export const useUndoStack = (stack: UndoStack) => { const forceUpdate = useForceUpdate(); useEffect(() => { stack.subscribe(forceUpdate); return () => { stack.unsubscribe(forceUpdate); }; }, [forceUpdate, stack]); return stack; }; /** * Allows using a state, while rerendering the component when it changes * and caching the return value of {@link State.getState} for better performance. * * @param state The state to use. * @param args The arguments for {@link State.getState}. * @returns The state and dispatchers in an array. * * @example * ```ts * // MyState: State<["name" | "surname"], string, { setState: (newState: string) => void }> * const MyComponent = (props: { type: "name" | "surname" }) => { * const [state, dispatchers] = useProjectState(MyState, props.type); * returndispatchers.setState("New state")}>{state}
; * } * ``` */ export const useProjectState = < GetStateArgs extends any[], StateShape, Dispatcher >( state: State