@@ -5,8 +5,9 @@ import React, {
55 createContext ,
66 useCallback ,
77 useContext ,
8+ useEffect ,
89 useMemo ,
9- useState ,
10+ useRef ,
1011} from 'react'
1112import {
1213 DEFAULT_MAX_CONCURRENT_REQUESTS ,
@@ -16,7 +17,6 @@ import {
1617import DataLoader from './dataloader'
1718import { OnErrorFn , PromiseType } from './types'
1819
19- type RequestQueue = Record < string , DataLoader >
2020type CachedData = Record < string , unknown >
2121type Reloads = Record < string , ( ) => Promise < void | unknown > >
2222
@@ -44,14 +44,17 @@ type GetReloadsFn = {
4444
4545export interface IDataLoaderContext {
4646 addRequest : ( key : string , args : UseDataLoaderInitializerArgs ) => DataLoader
47+ getOrAddRequest : (
48+ key : string ,
49+ args : UseDataLoaderInitializerArgs ,
50+ ) => DataLoader
4751 cacheKeyPrefix ?: string
4852 onError ?: ( error : Error ) => void | Promise < void >
4953 clearAllCachedData : ( ) => void
5054 clearCachedData : ( key : string ) => void
51- clearRequest : ( key : string ) => void
5255 getCachedData : GetCachedDataFn
5356 getReloads : GetReloadsFn
54- getRequest : ( key : string ) => DataLoader | undefined
57+ getRequest : ( key : string ) => DataLoader
5558 reload : ( key ?: string ) => Promise < void >
5659 reloadAll : ( ) => Promise < void >
5760}
@@ -70,34 +73,29 @@ const DataLoaderProvider = ({
7073 onError : OnErrorFn
7174 maxConcurrentRequests ?: number
7275} ) : ReactElement => {
73- const [ requests , setRequests ] = useState < RequestQueue > ( { } )
74-
76+ const requestsRef = useRef < Record < string , DataLoader > > ( { } )
7577 const computeKey = useCallback (
7678 ( key : string ) => `${ cacheKeyPrefix ? `${ cacheKeyPrefix } -` : '' } ${ key } ` ,
7779 [ cacheKeyPrefix ] ,
7880 )
7981
82+ const getRequest = useCallback (
83+ ( key : string ) => requestsRef . current [ computeKey ( key ) ] ,
84+ [ computeKey ] ,
85+ )
86+
8087 const addRequest = useCallback (
8188 ( key : string , args : UseDataLoaderInitializerArgs ) => {
8289 if ( DataLoader . maxConcurrent !== maxConcurrentRequests ) {
8390 DataLoader . maxConcurrent = maxConcurrentRequests as number
8491 }
8592 if ( key && typeof key === 'string' ) {
86- const notifyChanges = ( updatedRequest : DataLoader ) => {
87- setRequests ( current => ( {
88- ...current ,
89- [ updatedRequest . key ] : updatedRequest ,
90- } ) )
91- }
9293 const newRequest = new DataLoader ( {
9394 ...args ,
9495 key : computeKey ( key ) ,
95- notify : notifyChanges ,
9696 } )
97- setRequests ( current => ( {
98- ...current ,
99- [ newRequest . key ] : newRequest ,
100- } ) )
97+
98+ requestsRef . current [ newRequest . key ] = newRequest
10199
102100 return newRequest
103101 }
@@ -106,53 +104,32 @@ const DataLoaderProvider = ({
106104 [ computeKey , maxConcurrentRequests ] ,
107105 )
108106
109- const clearRequest = useCallback (
110- ( key : string ) => {
111- if ( key && typeof key === 'string' ) {
112- setRequests ( current => {
113- const newRequests = { ... current }
114- delete newRequests [ computeKey ( key ) ]
107+ const getOrAddRequest = useCallback (
108+ ( key : string , args : UseDataLoaderInitializerArgs ) => {
109+ const requestFound = getRequest ( key )
110+ if ( ! requestFound ) {
111+ return addRequest ( key , args )
112+ }
115113
116- return newRequests
117- } )
118- } else throw new Error ( KEY_IS_NOT_STRING_ERROR )
114+ return requestFound
119115 } ,
120- [ computeKey ] ,
121- )
122-
123- const getRequest = useCallback (
124- ( key : string ) => requests [ computeKey ( key ) ] ,
125- [ computeKey , requests ] ,
116+ [ addRequest , getRequest ] ,
126117 )
127118
128119 const clearCachedData = useCallback (
129120 ( key : string ) => {
130121 if ( typeof key === 'string' ) {
131- setRequests ( current => ( {
132- ...current ,
133- [ computeKey ( key ) ] : {
134- ...current [ computeKey ( key ) ] ,
135- data : undefined ,
136- } as DataLoader ,
137- } ) )
122+ if ( requestsRef . current [ computeKey ( key ) ] ) {
123+ requestsRef . current [ computeKey ( key ) ] . clearData ( )
124+ }
138125 } else throw new Error ( KEY_IS_NOT_STRING_ERROR )
139126 } ,
140127 [ computeKey ] ,
141128 )
142129 const clearAllCachedData = useCallback ( ( ) => {
143- setRequests ( current =>
144- Object . entries ( current ) . reduce (
145- ( acc , [ key , request ] ) =>
146- ( {
147- ...acc ,
148- [ key ] : {
149- ...request ,
150- data : undefined ,
151- } as DataLoader ,
152- } as RequestQueue ) ,
153- { } ,
154- ) ,
155- )
130+ Object . values ( requestsRef . current ) . forEach ( request => {
131+ request . clearData ( )
132+ } )
156133 } , [ ] )
157134
158135 const reload = useCallback (
@@ -166,25 +143,25 @@ const DataLoaderProvider = ({
166143
167144 const reloadAll = useCallback ( async ( ) => {
168145 await Promise . all (
169- Object . values ( requests ) . map ( request => request . load ( true ) ) ,
146+ Object . values ( requestsRef . current ) . map ( request => request . load ( true ) ) ,
170147 )
171- } , [ requests ] )
148+ } , [ ] )
172149
173150 const getCachedData = useCallback (
174151 ( key ?: string ) => {
175152 if ( key ) {
176- return getRequest ( key ) ?. data
153+ return getRequest ( key ) ?. getData ( )
177154 }
178155
179- return Object . entries ( requests ) . reduce (
180- ( acc , [ requestKey , { data } ] ) => ( {
156+ return Object . values ( requestsRef . current ) . reduce (
157+ ( acc , request ) => ( {
181158 ...acc ,
182- [ requestKey ] : data ,
159+ [ request . key ] : request . getData ( ) ,
183160 } ) ,
184161 { } as CachedData ,
185162 )
186163 } ,
187- [ getRequest , requests ] ,
164+ [ getRequest ] ,
188165 )
189166
190167 const getReloads = useCallback (
@@ -193,25 +170,41 @@ const DataLoaderProvider = ({
193170 return getRequest ( key ) ? ( ) => getRequest ( key ) . load ( true ) : undefined
194171 }
195172
196- return Object . entries ( requests ) . reduce (
173+ return Object . entries ( requestsRef . current ) . reduce (
197174 ( acc , [ requestKey , { load } ] ) => ( {
198175 ...acc ,
199176 [ requestKey ] : ( ) => load ( true ) ,
200177 } ) ,
201178 { } as Reloads ,
202179 )
203180 } ,
204- [ getRequest , requests ] ,
181+ [ getRequest ] ,
205182 )
206183
184+ useEffect ( ( ) => {
185+ const cleanRequest = ( ) => {
186+ setTimeout ( ( ) => {
187+ Object . keys ( requestsRef . current ) . forEach ( key => {
188+ if ( requestsRef . current [ key ] . getObserversCount ( ) === 0 ) {
189+ requestsRef . current [ key ] . destroy ( )
190+ delete requestsRef . current [ key ]
191+ }
192+ } )
193+ cleanRequest ( )
194+ } , 300 )
195+ }
196+
197+ cleanRequest ( )
198+ } , [ ] )
199+
207200 const value = useMemo (
208201 ( ) => ( {
209202 addRequest,
210203 cacheKeyPrefix,
211204 clearAllCachedData,
212205 clearCachedData,
213- clearRequest,
214206 getCachedData,
207+ getOrAddRequest,
215208 getReloads,
216209 getRequest,
217210 onError,
@@ -224,12 +217,12 @@ const DataLoaderProvider = ({
224217 clearAllCachedData ,
225218 clearCachedData ,
226219 getCachedData ,
220+ getOrAddRequest ,
227221 getRequest ,
228222 getReloads ,
229223 onError ,
230224 reload ,
231225 reloadAll ,
232- clearRequest ,
233226 ] ,
234227 )
235228
0 commit comments