@@ -7,87 +7,158 @@ import React, {
77 useContext ,
88 useMemo ,
99 useRef ,
10+ useState ,
1011} from 'react'
12+ import { KEY_IS_NOT_STRING_ERROR , StatusEnum } from './constants'
13+ import DataLoader from './dataloader'
14+ import { OnErrorFn , PromiseType } from './types'
15+
16+ type RequestQueue = Record < string , DataLoader >
17+ type CachedData = Record < string , unknown >
18+ type Reloads = Record < string , ( ) => Promise < void | unknown > >
19+
20+ type UseDataLoaderInitializerArgs < T = unknown > = {
21+ enabled ?: boolean
22+ key : string
23+ status ?: StatusEnum
24+ method : ( ) => PromiseType < T >
25+ pollingInterval ?: number
26+ keepPreviousData ?: boolean
27+ }
1128
1229interface Context {
13- addCachedData : ( key : string , newData : unknown ) => void ;
14- addReload : ( key : string , method : ( ) => Promise < void > ) => void ;
15- cacheKeyPrefix : string ;
30+ addCachedData : ( key : string , newData : unknown ) => void
31+ addReload : ( key : string , method : ( ) => Promise < void | unknown > ) => void
32+ addRequest : ( key : string , args : UseDataLoaderInitializerArgs ) => DataLoader
33+ cacheKeyPrefix : string
1634 onError ?: ( error : Error ) => void | Promise < void >
17- clearAllCachedData : ( ) => void ;
18- clearAllReloads : ( ) => void ;
19- clearCachedData : ( key ?: string | undefined ) => void ;
20- clearReload : ( key ?: string | undefined ) => void ;
21- getCachedData : ( key ?: string | undefined ) => unknown ;
22- getReloads : ( key ?: string | undefined ) => ( ( ) => Promise < void > ) | Reloads ;
23- reload : ( key ?: string | undefined ) => Promise < void > ;
24- reloadAll : ( ) => Promise < void > ;
35+ clearAllCachedData : ( ) => void
36+ clearAllReloads : ( ) => void
37+ clearCachedData : ( key ?: string ) => void
38+ clearReload : ( key ?: string ) => void
39+ getCachedData : ( key ?: string ) => unknown | CachedData
40+ getReloads : ( key ?: string ) => ( ( ) => Promise < void | unknown > ) | Reloads
41+ getRequest : ( key : string ) => DataLoader | undefined
42+ reload : ( key ?: string ) => Promise < void >
43+ reloadAll : ( ) => Promise < void >
2544}
2645
27- type CachedData = Record < string , unknown >
28- type Reloads = Record < string , ( ) => Promise < void > >
29-
3046// @ts -expect-error we force the context to undefined, should be corrected with default values
3147export const DataLoaderContext = createContext < Context > ( undefined )
3248
33- const DataLoaderProvider = ( { children, cacheKeyPrefix, onError } : {
34- children : ReactNode , cacheKeyPrefix : string , onError : ( error : Error ) => void | Promise < void >
49+ const DataLoaderProvider = ( {
50+ children,
51+ cacheKeyPrefix,
52+ onError,
53+ } : {
54+ children : ReactNode
55+ cacheKeyPrefix : string
56+ onError : OnErrorFn
3557} ) : ReactElement => {
36- const cachedData = useRef < CachedData > ( { } )
58+ const [ requestQueue , setRequestQueue ] = useState ( { } as RequestQueue )
59+ const [ cachedData , setCachedDataPrivate ] = useState < CachedData > ( { } )
3760 const reloads = useRef < Reloads > ( { } )
3861
39- const setCachedData = useCallback ( ( compute : CachedData | ( ( data : CachedData ) => CachedData ) ) => {
40- if ( typeof compute === 'function' ) {
41- cachedData . current = compute ( cachedData . current )
42- } else {
43- cachedData . current = compute
44- }
45- } , [ ] )
62+ const computeKey = useCallback (
63+ ( key : string ) => `${ cacheKeyPrefix ? `${ cacheKeyPrefix } -` : '' } ${ key } ` ,
64+ [ cacheKeyPrefix ] ,
65+ )
4666
47- const setReloads = useCallback ( ( compute : Reloads | ( ( data : Reloads ) => Reloads ) ) => {
48- if ( typeof compute === 'function' ) {
49- reloads . current = compute ( reloads . current )
50- } else {
51- reloads . current = compute
52- }
53- } , [ ] )
67+ const setCachedData = useCallback (
68+ ( compute : CachedData | ( ( data : CachedData ) => CachedData ) ) => {
69+ if ( typeof compute === 'function' ) {
70+ setCachedDataPrivate ( current => compute ( current ) )
71+ } else {
72+ setCachedDataPrivate ( compute )
73+ }
74+ } ,
75+ [ ] ,
76+ )
77+
78+ const setReloads = useCallback (
79+ ( compute : Reloads | ( ( data : Reloads ) => Reloads ) ) => {
80+ if ( typeof compute === 'function' ) {
81+ reloads . current = compute ( reloads . current )
82+ } else {
83+ reloads . current = compute
84+ }
85+ } ,
86+ [ ] ,
87+ )
5488
5589 const addCachedData = useCallback (
5690 ( key : string , newData : unknown ) => {
57- if ( key && typeof key === 'string' && newData ) {
58- setCachedData ( actualCachedData => ( {
59- ...actualCachedData ,
60- [ key ] : newData ,
61- } ) )
91+ if ( newData ) {
92+ if ( key && typeof key === 'string' ) {
93+ setCachedData ( actualCachedData => ( {
94+ ...actualCachedData ,
95+ [ computeKey ( key ) ] : newData ,
96+ } ) )
97+ } else throw new Error ( KEY_IS_NOT_STRING_ERROR )
6298 }
6399 } ,
64- [ setCachedData ] ,
100+ [ setCachedData , computeKey ] ,
65101 )
66102
67103 const addReload = useCallback (
68- ( key : string , method : ( ) => Promise < void > ) => {
69- if ( key && typeof key === 'string' && method ) {
70- setReloads ( actualReloads => ( {
71- ...actualReloads ,
72- [ key ] : method ,
104+ ( key : string , method : ( ) => Promise < void | unknown > ) => {
105+ if ( method ) {
106+ if ( key && typeof key === 'string' ) {
107+ setReloads ( actualReloads => ( {
108+ ...actualReloads ,
109+ [ computeKey ( key ) ] : method ,
110+ } ) )
111+ } else throw new Error ( KEY_IS_NOT_STRING_ERROR )
112+ }
113+ } ,
114+ [ setReloads , computeKey ] ,
115+ )
116+
117+ const addRequest = useCallback (
118+ ( key : string , args : UseDataLoaderInitializerArgs ) => {
119+ if ( key && typeof key === 'string' ) {
120+ const notifyChanges = ( updatedRequest : DataLoader ) => {
121+ setRequestQueue ( current => ( {
122+ ...current ,
123+ [ computeKey ( updatedRequest . key ) ] : updatedRequest ,
124+ } ) )
125+ }
126+ const newRequest = new DataLoader ( { ...args , notify : notifyChanges } )
127+ newRequest . addOnSuccessListener ( result => {
128+ if ( result !== undefined && result !== null )
129+ addCachedData ( key , result )
130+ } )
131+ setRequestQueue ( current => ( {
132+ ...current ,
133+ [ computeKey ( key ) ] : newRequest ,
73134 } ) )
135+
136+ addReload ( key , newRequest . launch )
137+
138+ return newRequest
74139 }
140+ throw new Error ( KEY_IS_NOT_STRING_ERROR )
75141 } ,
76- [ setReloads ] ,
142+ [ computeKey , addCachedData , addReload ] ,
143+ )
144+
145+ const getRequest = useCallback (
146+ ( key : string ) => requestQueue [ computeKey ( key ) ] ,
147+ [ computeKey , requestQueue ] ,
77148 )
78149
79150 const clearReload = useCallback (
80151 ( key ?: string ) => {
81152 if ( key && typeof key === 'string' ) {
82153 setReloads ( actualReloads => {
83154 const tmp = actualReloads
84- delete tmp [ key ]
155+ delete tmp [ computeKey ( key ) ]
85156
86157 return tmp
87158 } )
88- }
159+ } else throw new Error ( KEY_IS_NOT_STRING_ERROR )
89160 } ,
90- [ setReloads ] ,
161+ [ setReloads , computeKey ] ,
91162 )
92163
93164 const clearAllReloads = useCallback ( ( ) => {
@@ -99,70 +170,83 @@ const DataLoaderProvider = ({ children, cacheKeyPrefix, onError }: {
99170 if ( key && typeof key === 'string' ) {
100171 setCachedData ( actualCachedData => {
101172 const tmp = actualCachedData
102- delete tmp [ key ]
173+ delete tmp [ computeKey ( key ) ]
103174
104175 return tmp
105176 } )
106- }
177+ } else throw new Error ( KEY_IS_NOT_STRING_ERROR )
107178 } ,
108- [ setCachedData ] ,
179+ [ setCachedData , computeKey ] ,
109180 )
110181 const clearAllCachedData = useCallback ( ( ) => {
111182 setCachedData ( { } )
112183 } , [ setCachedData ] )
113184
114- const reload = useCallback ( async ( key ?: string ) => {
115- if ( key && typeof key === 'string' ) {
116- await ( reloads . current [ key ] && reloads . current [ key ] ( ) )
117- }
118- } , [ ] )
185+ const reload = useCallback (
186+ async ( key ?: string ) => {
187+ if ( key && typeof key === 'string' ) {
188+ await reloads . current [ computeKey ( key ) ] ?.( )
189+ } else throw new Error ( KEY_IS_NOT_STRING_ERROR )
190+ } ,
191+ [ computeKey ] ,
192+ )
119193
120194 const reloadAll = useCallback ( async ( ) => {
121195 await Promise . all (
122196 Object . values ( reloads . current ) . map ( reloadFn => reloadFn ( ) ) ,
123197 )
124198 } , [ ] )
125199
126- const getCachedData = useCallback ( ( key ?: string ) => {
127- if ( key ) {
128- return cachedData . current [ key ] || undefined
129- }
200+ const getCachedData = useCallback (
201+ ( key ?: string ) => {
202+ if ( key ) {
203+ return cachedData [ computeKey ( key ) ]
204+ }
130205
131- return cachedData . current
132- } , [ ] )
206+ return cachedData
207+ } ,
208+ [ computeKey , cachedData ] ,
209+ )
133210
134- const getReloads = useCallback ( ( key ?: string ) => {
135- if ( key ) {
136- return reloads . current [ key ] || undefined
137- }
211+ const getReloads = useCallback (
212+ ( key ?: string ) => {
213+ if ( key ) {
214+ return reloads . current [ computeKey ( key ) ]
215+ }
138216
139- return reloads . current
140- } , [ ] )
217+ return reloads . current
218+ } ,
219+ [ computeKey ] ,
220+ )
141221
142222 const value = useMemo (
143223 ( ) => ( {
144224 addCachedData,
145225 addReload,
226+ addRequest,
146227 cacheKeyPrefix,
147228 clearAllCachedData,
148229 clearAllReloads,
149230 clearCachedData,
150231 clearReload,
151232 getCachedData,
152233 getReloads,
234+ getRequest,
153235 onError,
154236 reload,
155237 reloadAll,
156238 } ) ,
157239 [
158240 addCachedData ,
159241 addReload ,
242+ addRequest ,
160243 cacheKeyPrefix ,
161244 clearAllCachedData ,
162245 clearAllReloads ,
163246 clearCachedData ,
164247 clearReload ,
165248 getCachedData ,
249+ getRequest ,
166250 getReloads ,
167251 onError ,
168252 reload ,
0 commit comments