@isograph/react-disposable-state 0.1.1 → 0.3.0

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.
Files changed (35) hide show
  1. package/dist/CacheItem.d.ts +1 -0
  2. package/dist/CacheItem.d.ts.map +1 -0
  3. package/dist/CacheItem.js +2 -2
  4. package/dist/ParentCache.d.ts +2 -1
  5. package/dist/ParentCache.d.ts.map +1 -0
  6. package/dist/ParentCache.js +3 -1
  7. package/dist/index.d.ts +2 -1
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +1 -1
  10. package/dist/{useCachedPrecommitValue.d.ts → useCachedResponsivePrecommitValue.d.ts} +12 -9
  11. package/dist/useCachedResponsivePrecommitValue.d.ts.map +1 -0
  12. package/dist/{useCachedPrecommitValue.js → useCachedResponsivePrecommitValue.js} +17 -16
  13. package/dist/useDisposableState.d.ts +2 -1
  14. package/dist/useDisposableState.d.ts.map +1 -0
  15. package/dist/useDisposableState.js +7 -6
  16. package/dist/useHasCommittedRef.d.ts +1 -0
  17. package/dist/useHasCommittedRef.d.ts.map +1 -0
  18. package/dist/useHasCommittedRef.js +1 -2
  19. package/dist/useLazyDisposableState.d.ts +4 -2
  20. package/dist/useLazyDisposableState.d.ts.map +1 -0
  21. package/dist/useLazyDisposableState.js +15 -12
  22. package/dist/useUpdatableDisposableState.d.ts +1 -0
  23. package/dist/useUpdatableDisposableState.d.ts.map +1 -0
  24. package/dist/useUpdatableDisposableState.js +2 -2
  25. package/package.json +11 -8
  26. package/src/ParentCache.ts +3 -1
  27. package/src/index.ts +1 -1
  28. package/src/useCachedResponsivePrecommitValue.test.tsx +571 -0
  29. package/src/{useCachedPrecommitValue.ts → useCachedResponsivePrecommitValue.ts} +18 -17
  30. package/src/useDisposableState.ts +12 -7
  31. package/src/useLazyDisposableState.test.tsx +70 -0
  32. package/src/useLazyDisposableState.ts +27 -15
  33. package/src/useUpdatableDisposableState.ts +1 -1
  34. package/tsconfig.json +6 -0
  35. package/src/useCachedPrecommitValue.test.tsx +0 -577
@@ -0,0 +1,70 @@
1
+ import { ItemCleanupPair } from '@isograph/disposable-types';
2
+ import React, { useEffect, useState } from 'react';
3
+ import { create } from 'react-test-renderer';
4
+ import { describe, expect, test, vi } from 'vitest';
5
+ import { ParentCache } from './ParentCache';
6
+ import { useLazyDisposableState } from './useLazyDisposableState';
7
+ function createCache<T>(value: T) {
8
+ const disposeItem = vi.fn();
9
+ const factory = vi.fn(() => {
10
+ const pair: ItemCleanupPair<T> = [value, disposeItem];
11
+ return pair;
12
+ });
13
+ const cache = new ParentCache(factory);
14
+ return { cache, disposeItem };
15
+ }
16
+
17
+ function promiseWithResolvers() {
18
+ let resolve;
19
+ let reject;
20
+ const promise = new Promise((_resolve, _reject) => {
21
+ resolve = _resolve;
22
+ reject = _reject;
23
+ });
24
+ return { resolve, reject, promise };
25
+ }
26
+
27
+ describe('useLazyDisposableState', async () => {
28
+ test('on cache change, it should dispose previous cache', async () => {
29
+ const cache1 = createCache(1);
30
+ const cache2 = createCache(2);
31
+ const renders = vi.fn();
32
+
33
+ let unmounted = promiseWithResolvers();
34
+ let committed = promiseWithResolvers();
35
+
36
+ function TestComponent() {
37
+ const [cache, setCache] = useState(cache1.cache);
38
+ const { state } = useLazyDisposableState(cache);
39
+
40
+ useEffect(() => {
41
+ setCache(cache2.cache);
42
+
43
+ return () => {
44
+ unmounted.resolve();
45
+ };
46
+ }, []);
47
+
48
+ useEffect(() => {
49
+ if (state == 1) return;
50
+ committed.resolve();
51
+ }, [state]);
52
+
53
+ renders(state);
54
+
55
+ return null;
56
+ }
57
+
58
+ const root = create(<TestComponent />, { unstable_isConcurrent: true });
59
+ await committed.promise;
60
+ expect(cache1.disposeItem).toHaveBeenCalled();
61
+ expect(cache1.cache.factory).toHaveBeenCalledOnce();
62
+ root.unmount();
63
+ await unmounted.promise;
64
+ expect(cache2.disposeItem).toHaveBeenCalled();
65
+ expect(cache2.cache.factory).toHaveBeenCalledOnce();
66
+ expect(renders).toHaveBeenNthCalledWith(1, 1);
67
+ expect(renders).toHaveBeenNthCalledWith(2, 2);
68
+ expect(renders).toHaveBeenCalledTimes(2);
69
+ });
70
+ });
@@ -1,40 +1,52 @@
1
1
  'use strict';
2
2
 
3
3
  import { useEffect, useRef } from 'react';
4
- import type { ItemCleanupPair } from '@isograph/disposable-types';
4
+
5
+ import type { ItemCleanupPair } from '@isograph/isograph-disposable-types';
5
6
  import { ParentCache } from './ParentCache';
6
- import { useCachedPrecommitValue } from './useCachedPrecommitValue';
7
+
8
+ import { type UnassignedState } from './useUpdatableDisposableState';
9
+ import { useCachedResponsivePrecommitValue } from './useCachedResponsivePrecommitValue';
7
10
 
8
11
  /**
9
12
  * useLazyDisposableState<T>
10
13
  * - Takes a mutable parent cache and a factory function
11
14
  * - Returns { state: T }
12
15
  *
13
- * This lazily loads the disposable item using useCachedPrecommitValue, then
16
+ * This lazily loads the disposable item using useCachedResponsivePrecommitValue, then
14
17
  * (on commit) sets it in state. The item continues to be returned after
15
18
  * commit and is disposed when the hook unmounts.
16
19
  */
17
- export function useLazyDisposableState<T>(parentCache: ParentCache<T>): {
20
+ export function useLazyDisposableState<T>(
21
+ parentCache: ParentCache<Exclude<T, UnassignedState>>,
22
+ ): {
18
23
  state: T;
19
24
  } {
20
25
  const itemCleanupPairRef = useRef<ItemCleanupPair<T> | null>(null);
21
26
 
22
- const preCommitItem = useCachedPrecommitValue(parentCache, (pair) => {
23
- itemCleanupPairRef.current = pair;
24
- });
27
+ const preCommitItem = useCachedResponsivePrecommitValue(
28
+ parentCache,
29
+ (pair) => {
30
+ itemCleanupPairRef.current?.[1]();
31
+ itemCleanupPairRef.current = pair;
32
+ },
33
+ );
25
34
 
26
35
  useEffect(() => {
27
- const cleanupFn = itemCleanupPairRef.current?.[1];
28
- // TODO confirm useEffect is called in order.
29
- if (cleanupFn == null) {
30
- throw new Error(
31
- 'cleanupFn unexpectedly null. This indicates a bug in react-disposable-state.',
32
- );
33
- }
34
- return cleanupFn;
36
+ return () => {
37
+ const cleanupFn = itemCleanupPairRef.current?.[1];
38
+ // TODO confirm useEffect is called in order.
39
+ if (cleanupFn == null) {
40
+ throw new Error(
41
+ 'cleanupFn unexpectedly null. This indicates a bug in react-disposable-state.',
42
+ );
43
+ }
44
+ return cleanupFn();
45
+ };
35
46
  }, []);
36
47
 
37
48
  const returnedItem = preCommitItem?.state ?? itemCleanupPairRef.current?.[0];
49
+
38
50
  if (returnedItem != null) {
39
51
  return { state: returnedItem };
40
52
  }
@@ -2,7 +2,7 @@ import { ItemCleanupPair } from '@isograph/disposable-types';
2
2
  import { useCallback, useEffect, useRef, useState } from 'react';
3
3
  import { useHasCommittedRef } from './useHasCommittedRef';
4
4
 
5
- export const UNASSIGNED_STATE = Symbol();
5
+ export const UNASSIGNED_STATE: unique symbol = Symbol();
6
6
  export type UnassignedState = typeof UNASSIGNED_STATE;
7
7
 
8
8
  type UseUpdatableDisposableStateReturnValue<T> = {
package/tsconfig.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.pkg.json",
3
+ "compilerOptions": {
4
+ "noEmit": true
5
+ }
6
+ }