import { useRouter } from "@tanstack/react-router"; import { useOptimistic, useState, useTransition } from "react"; function messageOf(error: unknown): string { return error instanceof Error && error.message ? error.message : "Something went wrong"; } /** * Applies a mutation's expected result immediately and keeps it until the server call and the * loader refresh both finish, so toggles like star/follow/watch never flash the stale value. * On failure the optimistic value is dropped automatically and the error is exposed. */ export function useOptimisticMutation( serverState: TState, reduce: (state: TState, input: TInput) => TState, action: (input: TInput) => Promise, ) { const router = useRouter(); const [state, apply] = useOptimistic(serverState, reduce); const [pending, startTransition] = useTransition(); const [error, setError] = useState(null); function run(input: TInput) { setError(null); startTransition(async () => { apply(input); try { await action(input); await router.invalidate(); } catch (caught) { setError(messageOf(caught)); } }); } return { state, run, pending, error }; }