| 1 | import { useEffect, useState } from "react"; |
| 2 | |
| 3 | /** |
| 4 | * `initial` until `promise` settles, then what it resolved to: for a value |
| 5 | * a loader streams in after the page, shown in place when it arrives. A |
| 6 | * promise that rejects leaves `initial`. |
| 7 | */ |
| 8 | export function useArrived<T, I = T>(promise: Promise<T>, initial: I): T | I { |
| 9 | const [arrived, setArrived] = useState<{ from: Promise<T>; value: T } | null>(null); |
| 10 | useEffect(() => { |
| 11 | let current = true; |
| 12 | promise.then( |
| 13 | (value) => current && setArrived({ from: promise, value }), |
| 14 | () => {}, |
| 15 | ); |
| 16 | return () => { |
| 17 | current = false; |
| 18 | }; |
| 19 | }, [promise]); |
| 20 | return arrived?.from === promise ? arrived.value : initial; |
| 21 | } |