Skip to content

Commit b145511

Browse files
fix: feedbacks and bugs
1 parent 3225c22 commit b145511

File tree

8 files changed

+292
-246
lines changed

8 files changed

+292
-246
lines changed

packages/use-dataloader/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ ReactDOM.render(
6363
)
6464
```
6565

66+
#### `maxConcurrentRequests`
67+
68+
You can specify a `maxConcurrentRequests` which will prevent DataLoader to launch request simultaneously and wait some to finish before start next ones.
69+
70+
This can be useful if you want to limit the number of concurrent requests.
71+
6672
#### `onError(err: Error): void | Promise<void>`
6773

6874
This is a global `onError` handler. It will be overriden if you specify one in `useDataLoader`

packages/use-dataloader/src/DataLoaderProvider.tsx

Lines changed: 56 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import React, {
55
createContext,
66
useCallback,
77
useContext,
8+
useEffect,
89
useMemo,
9-
useState,
10+
useRef,
1011
} from 'react'
1112
import {
1213
DEFAULT_MAX_CONCURRENT_REQUESTS,
@@ -16,7 +17,6 @@ import {
1617
import DataLoader from './dataloader'
1718
import { OnErrorFn, PromiseType } from './types'
1819

19-
type RequestQueue = Record<string, DataLoader>
2020
type CachedData = Record<string, unknown>
2121
type Reloads = Record<string, () => Promise<void | unknown>>
2222

@@ -44,14 +44,17 @@ type GetReloadsFn = {
4444

4545
export 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

Comments
 (0)