@@ -11,32 +11,57 @@ type Loadable<Value> =
1111 | { state : 'hasError' ; error : unknown }
1212 | { state : 'hasData' ; data : ResolveType < Value > }
1313
14+ const LOADING : Loadable < unknown > = { state : 'loading' }
15+
1416export function loadable < Value > ( anAtom : Atom < Value > ) : Atom < Loadable < Value > > {
1517 return memoizeAtom ( ( ) => {
16- // TODO we should revisit this for a better solution than refAtom
17- const refAtom = atom ( ( ) => ( { } as { prev ?: Loadable < Value > } ) )
18+ const loadableAtomCache = new WeakMap <
19+ Promise < void > ,
20+ Atom < Loadable < Value > >
21+ > ( )
1822
19- const derivedAtom = atom ( ( get ) : Loadable < Value > => {
20- const ref = get ( refAtom )
21- let curr = ref . prev
23+ const catchAtom = atom ( ( get ) => {
24+ let promise : Promise < void >
2225 try {
23- const value = get ( anAtom ) as ResolveType < Value >
24- if ( curr ?. state !== 'hasData' || ! Object . is ( curr . data , value ) ) {
25- curr = { state : 'hasData' , data : value }
26- }
26+ const data = get ( anAtom ) as ResolveType < Value >
27+ const loadableAtom = atom ( { state : 'hasData' , data } as Loadable < Value > )
28+ return loadableAtom
2729 } catch ( error ) {
2830 if ( error instanceof Promise ) {
29- if ( curr ?. state !== 'loading' ) {
30- curr = { state : 'loading' }
31- }
31+ promise = error
3232 } else {
33- if ( curr ?. state !== 'hasError' || ! Object . is ( curr . error , error ) ) {
34- curr = { state : 'hasError' , error }
33+ const loadableAtom = atom ( {
34+ state : 'hasError' ,
35+ error,
36+ } as Loadable < Value > )
37+ return loadableAtom
38+ }
39+ }
40+ const cached = loadableAtomCache . get ( promise )
41+ if ( cached ) {
42+ return cached
43+ }
44+ const loadableAtom = atom (
45+ LOADING as Loadable < Value > ,
46+ async ( get , set ) => {
47+ try {
48+ const data : Value = await get ( anAtom , { unstable_promise : true } )
49+ set ( loadableAtom , { state : 'hasData' , data } )
50+ } catch ( error ) {
51+ set ( loadableAtom , { state : 'hasError' , error } )
3552 }
3653 }
54+ )
55+ loadableAtom . onMount = ( init ) => {
56+ init ( )
3757 }
38- ref . prev = curr
39- return curr as Loadable < Value >
58+ loadableAtomCache . set ( promise , loadableAtom )
59+ return loadableAtom
60+ } )
61+
62+ const derivedAtom = atom ( ( get ) => {
63+ const loadableAtom = get ( catchAtom )
64+ return get ( loadableAtom )
4065 } )
4166
4267 return derivedAtom
0 commit comments