@isograph/react-disposable-state 0.0.0-main-6d83b6a2 → 0.0.0-main-f524690b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/useDisposableState.js +3 -1
- package/package.json +2 -2
- package/src/CacheItem.test.ts +158 -120
- package/src/CacheItem.ts +24 -7
- package/src/ParentCache.test.ts +2 -1
- package/src/ParentCache.ts +8 -6
- package/src/useCachedPrecommitValue.test.tsx +41 -11
- package/src/useCachedPrecommitValue.ts +7 -3
- package/src/useDisposableState.ts +5 -2
- package/src/useUpdatableDisposableState.test.tsx +12 -3
- package/src/useUpdatableDisposableState.ts +3 -1
@@ -44,7 +44,9 @@ function useDisposableState(parentCache) {
|
|
44
44
|
// Note that in the post-commit post-setState state, itemCleanupPairRef
|
45
45
|
// can still be assigned, during the render before the
|
46
46
|
// cleanupItemCleanupPairRefAfterSetState effect is called.
|
47
|
-
const state = (_c = (_a = (stateFromDisposableStateHook != useUpdatableDisposableState_1.UNASSIGNED_STATE
|
47
|
+
const state = (_c = (_a = (stateFromDisposableStateHook != useUpdatableDisposableState_1.UNASSIGNED_STATE
|
48
|
+
? stateFromDisposableStateHook
|
49
|
+
: null)) !== null && _a !== void 0 ? _a : (_b = itemCleanupPairRef.current) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : preCommitItem === null || preCommitItem === void 0 ? void 0 : preCommitItem.state;
|
48
50
|
return {
|
49
51
|
state: state,
|
50
52
|
setState,
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@isograph/react-disposable-state",
|
3
|
-
"version": "0.0.0-main-
|
3
|
+
"version": "0.0.0-main-f524690b",
|
4
4
|
"description": "Primitives for managing disposable state in React",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"types": "dist/index.d.ts",
|
@@ -16,7 +16,7 @@
|
|
16
16
|
"prepack": "yarn run compile"
|
17
17
|
},
|
18
18
|
"dependencies": {
|
19
|
-
"@isograph/disposable-types": "0.0.0-main-
|
19
|
+
"@isograph/disposable-types": "0.0.0-main-f524690b",
|
20
20
|
"react": "^18.2.0"
|
21
21
|
},
|
22
22
|
"devDependencies": {
|
package/src/CacheItem.test.ts
CHANGED
@@ -1,5 +1,17 @@
|
|
1
|
-
import {
|
2
|
-
|
1
|
+
import {
|
2
|
+
describe,
|
3
|
+
assert,
|
4
|
+
test,
|
5
|
+
vi,
|
6
|
+
beforeEach,
|
7
|
+
afterEach,
|
8
|
+
expect,
|
9
|
+
} from 'vitest';
|
10
|
+
import {
|
11
|
+
CacheItem,
|
12
|
+
CacheItemState,
|
13
|
+
createTemporarilyRetainedCacheItem,
|
14
|
+
} from './CacheItem';
|
3
15
|
import { ItemCleanupPair } from '@isograph/disposable-types';
|
4
16
|
|
5
17
|
function getState<T>(cacheItem: CacheItem<T>): CacheItemState<T> {
|
@@ -22,10 +34,11 @@ describe('CacheItem', () => {
|
|
22
34
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
23
35
|
return ret;
|
24
36
|
});
|
25
|
-
const [cacheItem, _disposeTemporaryRetain] =
|
26
|
-
|
27
|
-
|
28
|
-
|
37
|
+
const [cacheItem, _disposeTemporaryRetain] =
|
38
|
+
createTemporarilyRetainedCacheItem<number>(
|
39
|
+
factory,
|
40
|
+
removeFromParentCache,
|
41
|
+
);
|
29
42
|
|
30
43
|
expect(factory.mock.calls.length).toEqual(1);
|
31
44
|
|
@@ -47,10 +60,11 @@ describe('CacheItem', () => {
|
|
47
60
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
48
61
|
return ret;
|
49
62
|
});
|
50
|
-
const [cacheItem, disposeTemporaryRetain] =
|
51
|
-
|
52
|
-
|
53
|
-
|
63
|
+
const [cacheItem, disposeTemporaryRetain] =
|
64
|
+
createTemporarilyRetainedCacheItem<number>(
|
65
|
+
factory,
|
66
|
+
removeFromParentCache,
|
67
|
+
);
|
54
68
|
|
55
69
|
expect(factory.mock.calls.length).toEqual(1);
|
56
70
|
|
@@ -71,10 +85,11 @@ describe('CacheItem', () => {
|
|
71
85
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
72
86
|
return ret;
|
73
87
|
});
|
74
|
-
const [cacheItem, _disposeTemporaryRetain] =
|
75
|
-
|
76
|
-
|
77
|
-
|
88
|
+
const [cacheItem, _disposeTemporaryRetain] =
|
89
|
+
createTemporarilyRetainedCacheItem<number>(
|
90
|
+
factory,
|
91
|
+
removeFromParentCache,
|
92
|
+
);
|
78
93
|
|
79
94
|
expect(factory.mock.calls.length).toEqual(1);
|
80
95
|
|
@@ -95,10 +110,11 @@ describe('CacheItem', () => {
|
|
95
110
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
96
111
|
return ret;
|
97
112
|
});
|
98
|
-
const [cacheItem, disposeTemporaryRetain] =
|
99
|
-
|
100
|
-
|
101
|
-
|
113
|
+
const [cacheItem, disposeTemporaryRetain] =
|
114
|
+
createTemporarilyRetainedCacheItem<number>(
|
115
|
+
factory,
|
116
|
+
removeFromParentCache,
|
117
|
+
);
|
102
118
|
|
103
119
|
expect(factory.mock.calls.length).toEqual(1);
|
104
120
|
|
@@ -123,10 +139,11 @@ describe('CacheItem', () => {
|
|
123
139
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
124
140
|
return ret;
|
125
141
|
});
|
126
|
-
const [cacheItem, disposeTemporaryRetain] =
|
127
|
-
|
128
|
-
|
129
|
-
|
142
|
+
const [cacheItem, disposeTemporaryRetain] =
|
143
|
+
createTemporarilyRetainedCacheItem<number>(
|
144
|
+
factory,
|
145
|
+
removeFromParentCache,
|
146
|
+
);
|
130
147
|
|
131
148
|
expect(factory.mock.calls.length).toEqual(1);
|
132
149
|
|
@@ -152,18 +169,18 @@ describe('CacheItem', () => {
|
|
152
169
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
153
170
|
return ret;
|
154
171
|
});
|
155
|
-
const [cacheItem, disposeTemporaryRetain] =
|
156
|
-
|
157
|
-
|
158
|
-
|
172
|
+
const [cacheItem, disposeTemporaryRetain] =
|
173
|
+
createTemporarilyRetainedCacheItem<number>(
|
174
|
+
factory,
|
175
|
+
removeFromParentCache,
|
176
|
+
);
|
159
177
|
|
160
178
|
const mockedDisposeTemporaryRetain = vi.fn(disposeTemporaryRetain);
|
161
179
|
|
162
180
|
expect(factory.mock.calls.length).toEqual(1);
|
163
181
|
|
164
|
-
const [item, _disposePermanentRetain] =
|
165
|
-
mockedDisposeTemporaryRetain
|
166
|
-
)!;
|
182
|
+
const [item, _disposePermanentRetain] =
|
183
|
+
cacheItem.permanentRetainIfNotDisposed(mockedDisposeTemporaryRetain)!;
|
167
184
|
|
168
185
|
expect(item).toEqual(1);
|
169
186
|
expect(mockedDisposeTemporaryRetain.mock.calls.length).toEqual(1);
|
@@ -186,10 +203,11 @@ describe('CacheItem', () => {
|
|
186
203
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
187
204
|
return ret;
|
188
205
|
});
|
189
|
-
const [cacheItem, disposeTemporaryRetain] =
|
190
|
-
|
191
|
-
|
192
|
-
|
206
|
+
const [cacheItem, disposeTemporaryRetain] =
|
207
|
+
createTemporarilyRetainedCacheItem<number>(
|
208
|
+
factory,
|
209
|
+
removeFromParentCache,
|
210
|
+
);
|
193
211
|
|
194
212
|
expect(factory.mock.calls.length).toEqual(1);
|
195
213
|
|
@@ -209,18 +227,18 @@ describe('CacheItem', () => {
|
|
209
227
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
210
228
|
return ret;
|
211
229
|
});
|
212
|
-
const [cacheItem, disposeTemporaryRetain] =
|
213
|
-
|
214
|
-
|
215
|
-
|
230
|
+
const [cacheItem, disposeTemporaryRetain] =
|
231
|
+
createTemporarilyRetainedCacheItem<number>(
|
232
|
+
factory,
|
233
|
+
removeFromParentCache,
|
234
|
+
);
|
216
235
|
|
217
236
|
const mockedDisposeTemporaryRetain = vi.fn(disposeTemporaryRetain);
|
218
237
|
|
219
238
|
expect(factory.mock.calls.length).toEqual(1);
|
220
239
|
|
221
|
-
const [item, disposePermanentRetain] =
|
222
|
-
mockedDisposeTemporaryRetain
|
223
|
-
)!;
|
240
|
+
const [item, disposePermanentRetain] =
|
241
|
+
cacheItem.permanentRetainIfNotDisposed(mockedDisposeTemporaryRetain)!;
|
224
242
|
|
225
243
|
disposePermanentRetain();
|
226
244
|
|
@@ -238,18 +256,18 @@ describe('CacheItem', () => {
|
|
238
256
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
239
257
|
return ret;
|
240
258
|
});
|
241
|
-
const [cacheItem, disposeTemporaryRetain] =
|
242
|
-
|
243
|
-
|
244
|
-
|
259
|
+
const [cacheItem, disposeTemporaryRetain] =
|
260
|
+
createTemporarilyRetainedCacheItem<number>(
|
261
|
+
factory,
|
262
|
+
removeFromParentCache,
|
263
|
+
);
|
245
264
|
|
246
265
|
const mockedDisposeTemporaryRetain = vi.fn(disposeTemporaryRetain);
|
247
266
|
|
248
267
|
expect(factory.mock.calls.length).toEqual(1);
|
249
268
|
|
250
|
-
const [item, disposePermanentRetain] =
|
251
|
-
mockedDisposeTemporaryRetain
|
252
|
-
)!;
|
269
|
+
const [item, disposePermanentRetain] =
|
270
|
+
cacheItem.permanentRetainIfNotDisposed(mockedDisposeTemporaryRetain)!;
|
253
271
|
|
254
272
|
disposePermanentRetain();
|
255
273
|
expect(() => {
|
@@ -265,10 +283,11 @@ describe('CacheItem', () => {
|
|
265
283
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
266
284
|
return ret;
|
267
285
|
});
|
268
|
-
const [cacheItem, disposeTemporaryRetain] =
|
269
|
-
|
270
|
-
|
271
|
-
|
286
|
+
const [cacheItem, disposeTemporaryRetain] =
|
287
|
+
createTemporarilyRetainedCacheItem<number>(
|
288
|
+
factory,
|
289
|
+
removeFromParentCache,
|
290
|
+
);
|
272
291
|
|
273
292
|
expect(factory.mock.calls.length).toEqual(1);
|
274
293
|
|
@@ -278,7 +297,9 @@ describe('CacheItem', () => {
|
|
278
297
|
|
279
298
|
assert(state.kind === 'NotInParentCacheAndDisposed');
|
280
299
|
|
281
|
-
assert(
|
300
|
+
assert(
|
301
|
+
cacheItem.permanentRetainIfNotDisposed(disposeTemporaryRetain) === null,
|
302
|
+
);
|
282
303
|
|
283
304
|
expect(() => {
|
284
305
|
cacheItem.permanentRetain();
|
@@ -293,10 +314,11 @@ describe('CacheItem', () => {
|
|
293
314
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
294
315
|
return ret;
|
295
316
|
});
|
296
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
297
|
-
|
298
|
-
|
299
|
-
|
317
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
318
|
+
createTemporarilyRetainedCacheItem<number>(
|
319
|
+
factory,
|
320
|
+
removeFromParentCache,
|
321
|
+
);
|
300
322
|
|
301
323
|
const [_value, disposeOfPermanentRetain1] =
|
302
324
|
cacheItem.permanentRetainIfNotDisposed(disposeTemporaryRetain1)!;
|
@@ -316,10 +338,11 @@ describe('CacheItem', () => {
|
|
316
338
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
317
339
|
return ret;
|
318
340
|
});
|
319
|
-
const [cacheItem, _disposeTemporaryRetain1] =
|
320
|
-
|
321
|
-
|
322
|
-
|
341
|
+
const [cacheItem, _disposeTemporaryRetain1] =
|
342
|
+
createTemporarilyRetainedCacheItem<number>(
|
343
|
+
factory,
|
344
|
+
removeFromParentCache,
|
345
|
+
);
|
323
346
|
|
324
347
|
vi.advanceTimersByTime(1000);
|
325
348
|
|
@@ -346,10 +369,11 @@ describe('CacheItem', () => {
|
|
346
369
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
347
370
|
return ret;
|
348
371
|
});
|
349
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
350
|
-
|
351
|
-
|
352
|
-
|
372
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
373
|
+
createTemporarilyRetainedCacheItem<number>(
|
374
|
+
factory,
|
375
|
+
removeFromParentCache,
|
376
|
+
);
|
353
377
|
|
354
378
|
vi.advanceTimersByTime(1000);
|
355
379
|
const _disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -375,10 +399,11 @@ describe('CacheItem', () => {
|
|
375
399
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
376
400
|
return ret;
|
377
401
|
});
|
378
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
379
|
-
|
380
|
-
|
381
|
-
|
402
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
403
|
+
createTemporarilyRetainedCacheItem<number>(
|
404
|
+
factory,
|
405
|
+
removeFromParentCache,
|
406
|
+
);
|
382
407
|
|
383
408
|
vi.advanceTimersByTime(1000);
|
384
409
|
const _disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -398,10 +423,11 @@ describe('CacheItem', () => {
|
|
398
423
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
399
424
|
return ret;
|
400
425
|
});
|
401
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
402
|
-
|
403
|
-
|
404
|
-
|
426
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
427
|
+
createTemporarilyRetainedCacheItem<number>(
|
428
|
+
factory,
|
429
|
+
removeFromParentCache,
|
430
|
+
);
|
405
431
|
|
406
432
|
vi.advanceTimersByTime(1000);
|
407
433
|
const disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -420,10 +446,11 @@ describe('CacheItem', () => {
|
|
420
446
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
421
447
|
return ret;
|
422
448
|
});
|
423
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
424
|
-
|
425
|
-
|
426
|
-
|
449
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
450
|
+
createTemporarilyRetainedCacheItem<number>(
|
451
|
+
factory,
|
452
|
+
removeFromParentCache,
|
453
|
+
);
|
427
454
|
|
428
455
|
const disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
429
456
|
const state1 = getState(cacheItem);
|
@@ -445,10 +472,11 @@ describe('CacheItem', () => {
|
|
445
472
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
446
473
|
return ret;
|
447
474
|
});
|
448
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
449
|
-
|
450
|
-
|
451
|
-
|
475
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
476
|
+
createTemporarilyRetainedCacheItem<number>(
|
477
|
+
factory,
|
478
|
+
removeFromParentCache,
|
479
|
+
);
|
452
480
|
|
453
481
|
const disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
454
482
|
const state1 = getState(cacheItem);
|
@@ -470,10 +498,11 @@ describe('CacheItem', () => {
|
|
470
498
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
471
499
|
return ret;
|
472
500
|
});
|
473
|
-
const [cacheItem, _disposeTemporaryRetain1] =
|
474
|
-
|
475
|
-
|
476
|
-
|
501
|
+
const [cacheItem, _disposeTemporaryRetain1] =
|
502
|
+
createTemporarilyRetainedCacheItem<number>(
|
503
|
+
factory,
|
504
|
+
removeFromParentCache,
|
505
|
+
);
|
477
506
|
|
478
507
|
vi.advanceTimersByTime(1000);
|
479
508
|
const _disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -502,10 +531,11 @@ describe('CacheItem', () => {
|
|
502
531
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
503
532
|
return ret;
|
504
533
|
});
|
505
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
506
|
-
|
507
|
-
|
508
|
-
|
534
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
535
|
+
createTemporarilyRetainedCacheItem<number>(
|
536
|
+
factory,
|
537
|
+
removeFromParentCache,
|
538
|
+
);
|
509
539
|
|
510
540
|
vi.advanceTimersByTime(1000);
|
511
541
|
const _disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -529,10 +559,11 @@ describe('CacheItem', () => {
|
|
529
559
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
530
560
|
return ret;
|
531
561
|
});
|
532
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
533
|
-
|
534
|
-
|
535
|
-
|
562
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
563
|
+
createTemporarilyRetainedCacheItem<number>(
|
564
|
+
factory,
|
565
|
+
removeFromParentCache,
|
566
|
+
);
|
536
567
|
|
537
568
|
vi.advanceTimersByTime(1000);
|
538
569
|
const disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -560,10 +591,11 @@ describe('CacheItem', () => {
|
|
560
591
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
561
592
|
return ret;
|
562
593
|
});
|
563
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
564
|
-
|
565
|
-
|
566
|
-
|
594
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
595
|
+
createTemporarilyRetainedCacheItem<number>(
|
596
|
+
factory,
|
597
|
+
removeFromParentCache,
|
598
|
+
);
|
567
599
|
|
568
600
|
vi.advanceTimersByTime(1000);
|
569
601
|
const _disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -591,10 +623,11 @@ describe('CacheItem', () => {
|
|
591
623
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
592
624
|
return ret;
|
593
625
|
});
|
594
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
595
|
-
|
596
|
-
|
597
|
-
|
626
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
627
|
+
createTemporarilyRetainedCacheItem<number>(
|
628
|
+
factory,
|
629
|
+
removeFromParentCache,
|
630
|
+
);
|
598
631
|
|
599
632
|
vi.advanceTimersByTime(1000);
|
600
633
|
const _disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -618,10 +651,11 @@ describe('CacheItem', () => {
|
|
618
651
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
619
652
|
return ret;
|
620
653
|
});
|
621
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
622
|
-
|
623
|
-
|
624
|
-
|
654
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
655
|
+
createTemporarilyRetainedCacheItem<number>(
|
656
|
+
factory,
|
657
|
+
removeFromParentCache,
|
658
|
+
);
|
625
659
|
|
626
660
|
vi.advanceTimersByTime(1000);
|
627
661
|
const _disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -644,10 +678,11 @@ describe('CacheItem', () => {
|
|
644
678
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
645
679
|
return ret;
|
646
680
|
});
|
647
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
648
|
-
|
649
|
-
|
650
|
-
|
681
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
682
|
+
createTemporarilyRetainedCacheItem<number>(
|
683
|
+
factory,
|
684
|
+
removeFromParentCache,
|
685
|
+
);
|
651
686
|
|
652
687
|
vi.advanceTimersByTime(1000);
|
653
688
|
const disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -670,10 +705,11 @@ describe('CacheItem', () => {
|
|
670
705
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
671
706
|
return ret;
|
672
707
|
});
|
673
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
674
|
-
|
675
|
-
|
676
|
-
|
708
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
709
|
+
createTemporarilyRetainedCacheItem<number>(
|
710
|
+
factory,
|
711
|
+
removeFromParentCache,
|
712
|
+
);
|
677
713
|
|
678
714
|
vi.advanceTimersByTime(1000);
|
679
715
|
const disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -696,10 +732,11 @@ describe('CacheItem', () => {
|
|
696
732
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
697
733
|
return ret;
|
698
734
|
});
|
699
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
700
|
-
|
701
|
-
|
702
|
-
|
735
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
736
|
+
createTemporarilyRetainedCacheItem<number>(
|
737
|
+
factory,
|
738
|
+
removeFromParentCache,
|
739
|
+
);
|
703
740
|
|
704
741
|
vi.advanceTimersByTime(1000);
|
705
742
|
const _disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
@@ -724,10 +761,11 @@ describe('CacheItem', () => {
|
|
724
761
|
const ret: ItemCleanupPair<number> = [1, disposeItem];
|
725
762
|
return ret;
|
726
763
|
});
|
727
|
-
const [cacheItem, disposeTemporaryRetain1] =
|
728
|
-
|
729
|
-
|
730
|
-
|
764
|
+
const [cacheItem, disposeTemporaryRetain1] =
|
765
|
+
createTemporarilyRetainedCacheItem<number>(
|
766
|
+
factory,
|
767
|
+
removeFromParentCache,
|
768
|
+
);
|
731
769
|
|
732
770
|
vi.advanceTimersByTime(1000);
|
733
771
|
const disposeTemporaryRetain2 = cacheItem.temporaryRetain();
|
package/src/CacheItem.ts
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
import {
|
1
|
+
import {
|
2
|
+
CleanupFn,
|
3
|
+
Factory,
|
4
|
+
ItemCleanupPair,
|
5
|
+
} from '@isograph/disposable-types';
|
2
6
|
|
3
7
|
const DEFAULT_TEMPORARY_RETAIN_TIME = 5000;
|
4
8
|
|
@@ -103,7 +107,9 @@ export class CacheItem<T> {
|
|
103
107
|
}
|
104
108
|
}
|
105
109
|
|
106
|
-
permanentRetainIfNotDisposed(
|
110
|
+
permanentRetainIfNotDisposed(
|
111
|
+
disposeOfTemporaryRetain: CleanupFn,
|
112
|
+
): ItemCleanupPair<T> | null {
|
107
113
|
switch (this.__state.kind) {
|
108
114
|
case 'InParentCacheAndNotDisposed': {
|
109
115
|
let cleared = false;
|
@@ -127,7 +133,9 @@ export class CacheItem<T> {
|
|
127
133
|
}
|
128
134
|
case 'NotInParentCacheAndNotDisposed': {
|
129
135
|
this.__state.permanentRetainCount--;
|
130
|
-
this.__maybeExitNotInParentCacheAndNotDisposedState(
|
136
|
+
this.__maybeExitNotInParentCacheAndNotDisposedState(
|
137
|
+
this.__state,
|
138
|
+
);
|
131
139
|
return;
|
132
140
|
}
|
133
141
|
default: {
|
@@ -157,7 +165,9 @@ export class CacheItem<T> {
|
|
157
165
|
switch (this.__state.kind) {
|
158
166
|
case 'NotInParentCacheAndNotDisposed': {
|
159
167
|
this.__state.permanentRetainCount--;
|
160
|
-
this.__maybeExitNotInParentCacheAndNotDisposedState(
|
168
|
+
this.__maybeExitNotInParentCacheAndNotDisposedState(
|
169
|
+
this.__state,
|
170
|
+
);
|
161
171
|
return;
|
162
172
|
}
|
163
173
|
default: {
|
@@ -178,7 +188,10 @@ export class CacheItem<T> {
|
|
178
188
|
}
|
179
189
|
|
180
190
|
temporaryRetain(): CleanupFn {
|
181
|
-
type TemporaryRetainStatus =
|
191
|
+
type TemporaryRetainStatus =
|
192
|
+
| 'Uncleared'
|
193
|
+
| 'ClearedByCallback'
|
194
|
+
| 'ClearedByTimeout';
|
182
195
|
|
183
196
|
switch (this.__state.kind) {
|
184
197
|
case 'InParentCacheAndNotDisposed': {
|
@@ -308,7 +321,9 @@ export class CacheItem<T> {
|
|
308
321
|
}
|
309
322
|
}
|
310
323
|
|
311
|
-
private __maybeExitInParentCacheAndNotDisposedState(
|
324
|
+
private __maybeExitInParentCacheAndNotDisposedState(
|
325
|
+
state: InParentCacheAndNotDisposed<T>,
|
326
|
+
) {
|
312
327
|
if (state.temporaryRetainCount === 0 && state.permanentRetainCount === 0) {
|
313
328
|
state.removeFromParentCache();
|
314
329
|
state.disposeValue();
|
@@ -326,7 +341,9 @@ export class CacheItem<T> {
|
|
326
341
|
}
|
327
342
|
}
|
328
343
|
|
329
|
-
private __maybeExitNotInParentCacheAndNotDisposedState(
|
344
|
+
private __maybeExitNotInParentCacheAndNotDisposedState(
|
345
|
+
state: NotInParentCacheAndNotDisposed<T>,
|
346
|
+
) {
|
330
347
|
if (state.permanentRetainCount === 0) {
|
331
348
|
state.disposeValue();
|
332
349
|
this.__state = {
|
package/src/ParentCache.test.ts
CHANGED
@@ -15,7 +15,8 @@ describe('ParentCache', () => {
|
|
15
15
|
});
|
16
16
|
const parentCache = new ParentCache<number>(factory);
|
17
17
|
|
18
|
-
const [_cacheItem, value, clearTemporaryRetain] =
|
18
|
+
const [_cacheItem, value, clearTemporaryRetain] =
|
19
|
+
parentCache.getOrPopulateAndTemporaryRetain();
|
19
20
|
|
20
21
|
expect(factory.mock.calls.length).toBe(1);
|
21
22
|
assert(value === 1);
|
package/src/ParentCache.ts
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
import { CacheItem, createTemporarilyRetainedCacheItem } from './CacheItem';
|
2
|
-
import {
|
2
|
+
import {
|
3
|
+
CleanupFn,
|
4
|
+
Factory,
|
5
|
+
ItemCleanupPair,
|
6
|
+
} from '@isograph/disposable-types';
|
3
7
|
|
4
8
|
// TODO convert cache impl to a getter and setter and free functions
|
5
9
|
// TODO accept options that get passed to CacheItem
|
@@ -51,9 +55,8 @@ export class ParentCache<T> {
|
|
51
55
|
}
|
52
56
|
|
53
57
|
private __populateAndTemporaryRetain(): [CacheItem<T>, T, CleanupFn] {
|
54
|
-
const pair: ItemCleanupPair<CacheItem<T>> =
|
55
|
-
this.__factory,
|
56
|
-
() => {
|
58
|
+
const pair: ItemCleanupPair<CacheItem<T>> =
|
59
|
+
createTemporarilyRetainedCacheItem(this.__factory, () => {
|
57
60
|
// We are doing this check because we don't want to remove the cache item
|
58
61
|
// if it is not the one that was created when the temporary retain was created.
|
59
62
|
//
|
@@ -70,8 +73,7 @@ export class ParentCache<T> {
|
|
70
73
|
if (this.__cacheItem === pair[0]) {
|
71
74
|
this.empty();
|
72
75
|
}
|
73
|
-
}
|
74
|
-
);
|
76
|
+
});
|
75
77
|
|
76
78
|
// We deconstruct this here instead of at the definition site because otherwise,
|
77
79
|
// typescript thinks that cacheItem is any, because it's referenced in the closure.
|
@@ -52,7 +52,10 @@ function promiseAndResolver() {
|
|
52
52
|
// The fact that sometimes we need to render in concurrent mode and sometimes
|
53
53
|
// not is a bit worrisome.
|
54
54
|
async function awaitableCreate(Component, isConcurrent) {
|
55
|
-
const element = create(
|
55
|
+
const element = create(
|
56
|
+
Component,
|
57
|
+
isConcurrent ? { unstable_isConcurrent: true } : undefined,
|
58
|
+
);
|
56
59
|
await shortPromise();
|
57
60
|
return element;
|
58
61
|
}
|
@@ -65,7 +68,10 @@ describe('useCachedPrecommitValue', () => {
|
|
65
68
|
return pair;
|
66
69
|
});
|
67
70
|
const cache = new ParentCache(factory);
|
68
|
-
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
71
|
+
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
72
|
+
cache,
|
73
|
+
'getOrPopulateAndTemporaryRetain',
|
74
|
+
);
|
69
75
|
|
70
76
|
const componentCommits = vi.fn();
|
71
77
|
const hookOnCommit = vi.fn();
|
@@ -189,7 +195,10 @@ describe('useCachedPrecommitValue', () => {
|
|
189
195
|
return pair;
|
190
196
|
});
|
191
197
|
const cache = new ParentCache(factory);
|
192
|
-
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
198
|
+
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
199
|
+
cache,
|
200
|
+
'getOrPopulateAndTemporaryRetain',
|
201
|
+
);
|
193
202
|
|
194
203
|
const componentCommits = vi.fn();
|
195
204
|
const hookOnCommit = vi.fn();
|
@@ -203,7 +212,9 @@ describe('useCachedPrecommitValue', () => {
|
|
203
212
|
expect(factory).toHaveBeenCalledTimes(1);
|
204
213
|
|
205
214
|
renderCount++;
|
206
|
-
expect(getOrPopulateAndTemporaryRetain).toHaveBeenCalledTimes(
|
215
|
+
expect(getOrPopulateAndTemporaryRetain).toHaveBeenCalledTimes(
|
216
|
+
renderCount,
|
217
|
+
);
|
207
218
|
|
208
219
|
React.useEffect(() => {
|
209
220
|
componentCommits();
|
@@ -249,7 +260,10 @@ describe('useCachedPrecommitValue', () => {
|
|
249
260
|
});
|
250
261
|
const cache = new ParentCache(factory);
|
251
262
|
|
252
|
-
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
263
|
+
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
264
|
+
cache,
|
265
|
+
'getOrPopulateAndTemporaryRetain',
|
266
|
+
);
|
253
267
|
|
254
268
|
const componentCommits = vi.fn();
|
255
269
|
const hookOnCommit = vi.fn();
|
@@ -318,8 +332,14 @@ describe('useCachedPrecommitValue', () => {
|
|
318
332
|
return pair;
|
319
333
|
});
|
320
334
|
const cache = new ParentCache(factory);
|
321
|
-
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
322
|
-
|
335
|
+
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
336
|
+
cache,
|
337
|
+
'getOrPopulateAndTemporaryRetain',
|
338
|
+
);
|
339
|
+
const getAndPermanentRetainIfPresent = vi.spyOn(
|
340
|
+
cache,
|
341
|
+
'getAndPermanentRetainIfPresent',
|
342
|
+
);
|
323
343
|
|
324
344
|
const componentCommits = vi.fn();
|
325
345
|
const hookOnCommit = vi.fn();
|
@@ -333,7 +353,9 @@ describe('useCachedPrecommitValue', () => {
|
|
333
353
|
componentCommits();
|
334
354
|
expect(getOrPopulateAndTemporaryRetain).toHaveBeenCalledTimes(1);
|
335
355
|
expect(getAndPermanentRetainIfPresent).toHaveBeenCalledTimes(1);
|
336
|
-
expect(getAndPermanentRetainIfPresent.mock.results[0].value).toBe(
|
356
|
+
expect(getAndPermanentRetainIfPresent.mock.results[0].value).toBe(
|
357
|
+
null,
|
358
|
+
);
|
337
359
|
expect(factory).toHaveBeenCalledTimes(2);
|
338
360
|
expect(cache.isEmpty()).toBe(true);
|
339
361
|
expect(hookOnCommit).toHaveBeenCalledTimes(1);
|
@@ -403,7 +425,10 @@ describe('useCachedPrecommitValue', () => {
|
|
403
425
|
return pair;
|
404
426
|
});
|
405
427
|
const cache = new ParentCache(factory);
|
406
|
-
const getAndPermanentRetainIfPresent = vi.spyOn(
|
428
|
+
const getAndPermanentRetainIfPresent = vi.spyOn(
|
429
|
+
cache,
|
430
|
+
'getAndPermanentRetainIfPresent',
|
431
|
+
);
|
407
432
|
|
408
433
|
const componentCommits = vi.fn();
|
409
434
|
const hookOnCommit = vi.fn();
|
@@ -417,7 +442,9 @@ describe('useCachedPrecommitValue', () => {
|
|
417
442
|
// Note that we called getOrPopulateAndTemporaryRetain during CodeExecutor, hence 2
|
418
443
|
expect(getOrPopulateAndTemporaryRetain).toHaveBeenCalledTimes(2);
|
419
444
|
expect(getAndPermanentRetainIfPresent).toHaveBeenCalledTimes(1);
|
420
|
-
expect(getAndPermanentRetainIfPresent.mock.results[0].value[0]).toBe(
|
445
|
+
expect(getAndPermanentRetainIfPresent.mock.results[0].value[0]).toBe(
|
446
|
+
2,
|
447
|
+
);
|
421
448
|
expect(factory).toHaveBeenCalledTimes(2);
|
422
449
|
expect(hookOnCommit).toHaveBeenCalledTimes(1);
|
423
450
|
expect(hookOnCommit.mock.calls[0][0][0]).toBe(2);
|
@@ -426,7 +453,10 @@ describe('useCachedPrecommitValue', () => {
|
|
426
453
|
return <div />;
|
427
454
|
}
|
428
455
|
|
429
|
-
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
456
|
+
const getOrPopulateAndTemporaryRetain = vi.spyOn(
|
457
|
+
cache,
|
458
|
+
'getOrPopulateAndTemporaryRetain',
|
459
|
+
);
|
430
460
|
|
431
461
|
// wat is going on?
|
432
462
|
//
|
@@ -65,13 +65,16 @@ export function useCachedPrecommitValue<T>(
|
|
65
65
|
//
|
66
66
|
// After the above, we have a non-disposed item and a cleanup function, which we
|
67
67
|
// can pass to onCommit.
|
68
|
-
const undisposedPair = cacheItem.permanentRetainIfNotDisposed(
|
68
|
+
const undisposedPair = cacheItem.permanentRetainIfNotDisposed(
|
69
|
+
disposeOfTemporaryRetain,
|
70
|
+
);
|
69
71
|
if (undisposedPair !== null) {
|
70
72
|
onCommit(undisposedPair);
|
71
73
|
} else {
|
72
74
|
// The cache item we created during render has been disposed. Check if the parent
|
73
75
|
// cache is populated.
|
74
|
-
const existingCacheItemCleanupPair =
|
76
|
+
const existingCacheItemCleanupPair =
|
77
|
+
parentCache.getAndPermanentRetainIfPresent();
|
75
78
|
if (existingCacheItemCleanupPair !== null) {
|
76
79
|
onCommit(existingCacheItemCleanupPair);
|
77
80
|
} else {
|
@@ -94,7 +97,8 @@ export function useCachedPrecommitValue<T>(
|
|
94
97
|
|
95
98
|
// Safety: item is only safe to use (i.e. guaranteed not to have disposed)
|
96
99
|
// during this tick.
|
97
|
-
const [cacheItem, item, disposeOfTemporaryRetain] =
|
100
|
+
const [cacheItem, item, disposeOfTemporaryRetain] =
|
101
|
+
parentCache.getOrPopulateAndTemporaryRetain();
|
98
102
|
|
99
103
|
return { state: item };
|
100
104
|
}
|
@@ -22,7 +22,8 @@ export function useDisposableState<T = never>(
|
|
22
22
|
itemCleanupPairRef.current = pair;
|
23
23
|
});
|
24
24
|
|
25
|
-
const { state: stateFromDisposableStateHook, setState } =
|
25
|
+
const { state: stateFromDisposableStateHook, setState } =
|
26
|
+
useUpdatableDisposableState<T>();
|
26
27
|
|
27
28
|
useEffect(
|
28
29
|
function cleanupItemCleanupPairRefAfterSetState() {
|
@@ -64,7 +65,9 @@ export function useDisposableState<T = never>(
|
|
64
65
|
// can still be assigned, during the render before the
|
65
66
|
// cleanupItemCleanupPairRefAfterSetState effect is called.
|
66
67
|
const state: T | undefined =
|
67
|
-
(stateFromDisposableStateHook != UNASSIGNED_STATE
|
68
|
+
(stateFromDisposableStateHook != UNASSIGNED_STATE
|
69
|
+
? stateFromDisposableStateHook
|
70
|
+
: null) ??
|
68
71
|
itemCleanupPairRef.current?.[0] ??
|
69
72
|
preCommitItem?.state;
|
70
73
|
|
@@ -1,7 +1,10 @@
|
|
1
1
|
import { describe, test, vi, expect } from 'vitest';
|
2
2
|
import React from 'react';
|
3
3
|
import { create } from 'react-test-renderer';
|
4
|
-
import {
|
4
|
+
import {
|
5
|
+
useUpdatableDisposableState,
|
6
|
+
UNASSIGNED_STATE,
|
7
|
+
} from './useUpdatableDisposableState';
|
5
8
|
|
6
9
|
function Suspender({ promise, isResolvedRef }) {
|
7
10
|
if (!isResolvedRef.current) {
|
@@ -41,7 +44,10 @@ function promiseAndResolver() {
|
|
41
44
|
// The fact that sometimes we need to render in concurrent mode and sometimes
|
42
45
|
// not is a bit worrisome.
|
43
46
|
async function awaitableCreate(Component, isConcurrent) {
|
44
|
-
const element = create(
|
47
|
+
const element = create(
|
48
|
+
Component,
|
49
|
+
isConcurrent ? { unstable_isConcurrent: true } : undefined,
|
50
|
+
);
|
45
51
|
await shortPromise();
|
46
52
|
return element;
|
47
53
|
}
|
@@ -446,7 +452,10 @@ describe('useUpdatableDisposableState', () => {
|
|
446
452
|
|
447
453
|
const shouldMountRef = { current: true };
|
448
454
|
|
449
|
-
await awaitableCreate(
|
455
|
+
await awaitableCreate(
|
456
|
+
<ParentComponent shouldMountRef={shouldMountRef} />,
|
457
|
+
true,
|
458
|
+
);
|
450
459
|
|
451
460
|
expect(render).toHaveBeenCalledTimes(1);
|
452
461
|
expect(componentCommits).toHaveBeenCalledTimes(1);
|
@@ -66,7 +66,9 @@ export function useUpdatableDisposableState<
|
|
66
66
|
const undisposedICIs = useRef(new Set<ICI<T>>());
|
67
67
|
const setStateCountRef = useRef(0);
|
68
68
|
|
69
|
-
const [stateICI, setStateICI] = useState<ICI<T> | UnassignedState>(
|
69
|
+
const [stateICI, setStateICI] = useState<ICI<T> | UnassignedState>(
|
70
|
+
UNASSIGNED_STATE,
|
71
|
+
);
|
70
72
|
|
71
73
|
const setStateAfterCommit = useCallback(
|
72
74
|
(itemCleanupPair: ItemCleanupPair<T>) => {
|