@assistant-ui/tap 0.5.13 → 0.6.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.
- package/README.md +9 -8
- package/dist/core/ResourceFiber.d.ts.map +1 -1
- package/dist/core/ResourceFiber.js +3 -2
- package/dist/core/ResourceFiber.js.map +1 -1
- package/dist/core/context.d.ts +13 -6
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +19 -6
- package/dist/core/context.js.map +1 -1
- package/dist/core/createResourceRoot.d.ts +2 -1
- package/dist/core/createResourceRoot.d.ts.map +1 -1
- package/dist/core/createResourceRoot.js +2 -2
- package/dist/core/createResourceRoot.js.map +1 -1
- package/dist/core/helpers/commit.d.ts.map +1 -1
- package/dist/core/helpers/execution-context.d.ts +2 -1
- package/dist/core/helpers/execution-context.d.ts.map +1 -1
- package/dist/core/helpers/execution-context.js +4 -1
- package/dist/core/helpers/execution-context.js.map +1 -1
- package/dist/core/helpers/root.d.ts.map +1 -1
- package/dist/core/helpers/root.js.map +1 -1
- package/dist/core/react-dispatcher.d.ts +12 -0
- package/dist/core/react-dispatcher.d.ts.map +1 -0
- package/dist/core/react-dispatcher.js +62 -0
- package/dist/core/react-dispatcher.js.map +1 -0
- package/dist/core/resource.d.ts.map +1 -1
- package/dist/core/scheduler.d.ts.map +1 -1
- package/dist/core/scheduler.js +1 -1
- package/dist/core/scheduler.js.map +1 -1
- package/dist/core/types.d.ts +3 -3
- package/dist/core/withKey.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +13 -0
- package/dist/hooks/index.js +13 -0
- package/dist/hooks/use.d.ts +9 -0
- package/dist/hooks/use.d.ts.map +1 -0
- package/dist/hooks/use.js +14 -0
- package/dist/hooks/use.js.map +1 -0
- package/dist/hooks/useCallback.d.ts +5 -0
- package/dist/hooks/useCallback.d.ts.map +1 -0
- package/dist/hooks/useCallback.js +9 -0
- package/dist/hooks/useCallback.js.map +1 -0
- package/dist/hooks/useEffect.d.ts +10 -0
- package/dist/hooks/useEffect.d.ts.map +1 -0
- package/dist/hooks/{tap-effect.js → useEffect.js} +7 -7
- package/dist/hooks/useEffect.js.map +1 -0
- package/dist/hooks/{tap-effect-event.d.ts → useEffectEvent.d.ts} +5 -5
- package/dist/hooks/useEffectEvent.d.ts.map +1 -0
- package/dist/hooks/{tap-effect-event.js → useEffectEvent.js} +12 -12
- package/dist/hooks/useEffectEvent.js.map +1 -0
- package/dist/hooks/useMemo.d.ts +5 -0
- package/dist/hooks/useMemo.d.ts.map +1 -0
- package/dist/hooks/{tap-memo.js → useMemo.js} +6 -6
- package/dist/hooks/useMemo.js.map +1 -0
- package/dist/hooks/useMemoCache.d.ts +10 -0
- package/dist/hooks/useMemoCache.d.ts.map +1 -0
- package/dist/hooks/useMemoCache.js +21 -0
- package/dist/hooks/useMemoCache.js.map +1 -0
- package/dist/hooks/useReducer.d.ts +21 -0
- package/dist/hooks/useReducer.d.ts.map +1 -0
- package/dist/hooks/{tap-reducer.js → useReducer.js} +10 -10
- package/dist/hooks/useReducer.js.map +1 -0
- package/dist/hooks/useRef.d.ts +11 -0
- package/dist/hooks/useRef.d.ts.map +1 -0
- package/dist/hooks/useRef.js +10 -0
- package/dist/hooks/useRef.js.map +1 -0
- package/dist/{react/use-resource.d.ts → hooks/useResource.d.ts} +3 -2
- package/dist/hooks/useResource.d.ts.map +1 -0
- package/dist/hooks/{tap-resource.js → useResource.js} +12 -12
- package/dist/hooks/useResource.js.map +1 -0
- package/dist/hooks/useResourceRoot.d.ts +20 -0
- package/dist/hooks/useResourceRoot.d.ts.map +1 -0
- package/dist/{tapResourceRoot.js → hooks/useResourceRoot.js} +30 -26
- package/dist/hooks/useResourceRoot.js.map +1 -0
- package/dist/hooks/{tap-resources.d.ts → useResources.d.ts} +4 -4
- package/dist/hooks/useResources.d.ts.map +1 -0
- package/dist/hooks/{tap-resources.js → useResources.js} +28 -23
- package/dist/hooks/useResources.js.map +1 -0
- package/dist/hooks/useState.d.ts +9 -0
- package/dist/hooks/useState.d.ts.map +1 -0
- package/dist/hooks/useState.js +11 -0
- package/dist/hooks/useState.js.map +1 -0
- package/dist/hooks/utils/useCell.d.ts +10 -0
- package/dist/hooks/utils/useCell.d.ts.map +1 -0
- package/dist/hooks/utils/{tapHook.js → useCell.js} +4 -4
- package/dist/hooks/utils/{tapHook.js.map → useCell.js.map} +1 -1
- package/dist/index.d.ts +3 -13
- package/dist/index.js +3 -13
- package/dist/react/hooks.d.ts +25 -0
- package/dist/react/hooks.d.ts.map +1 -0
- package/dist/react/hooks.js +69 -0
- package/dist/react/hooks.js.map +1 -0
- package/dist/react-shim/index.d.ts +19 -0
- package/dist/react-shim/index.d.ts.map +1 -0
- package/dist/react-shim/index.js +28 -0
- package/dist/react-shim/index.js.map +1 -0
- package/package.json +13 -16
- package/react-shim/package.json +4 -0
- package/src/__tests__/basic/resourceHandle.test.ts +7 -3
- package/src/__tests__/basic/tapEffect.basic.test.ts +19 -21
- package/src/__tests__/basic/tapReducer.basic.test.ts +14 -14
- package/src/__tests__/basic/tapResources.basic.test.ts +19 -14
- package/src/__tests__/basic/tapState.basic.test.ts +20 -20
- package/src/__tests__/errors/errors.effect-errors.test.ts +21 -21
- package/src/__tests__/errors/errors.render-errors.test.ts +18 -18
- package/src/__tests__/lifecycle/lifecycle.dependencies.test.ts +25 -25
- package/src/__tests__/lifecycle/lifecycle.mount-unmount.test.ts +17 -21
- package/src/__tests__/react/concurrent-mode.test.tsx +7 -7
- package/src/__tests__/react/react-shim.test.tsx +65 -0
- package/src/__tests__/react/useResource.test.tsx +172 -0
- package/src/__tests__/react-dispatcher.test.ts +74 -0
- package/src/__tests__/rules/rules.hook-count.test.ts +30 -29
- package/src/__tests__/rules/rules.hook-order.test.ts +27 -27
- package/src/__tests__/strictmode/react-strictmode-behavior.test.tsx +1 -4
- package/src/__tests__/strictmode/strictmode.test.ts +42 -42
- package/src/__tests__/strictmode/tap-strictmode-rerender-sources.test.ts +55 -58
- package/src/__tests__/test-utils.ts +2 -3
- package/src/core/ResourceFiber.ts +4 -1
- package/src/core/context.ts +31 -9
- package/src/core/createResourceRoot.ts +4 -4
- package/src/core/helpers/execution-context.ts +4 -0
- package/src/core/helpers/root.ts +0 -1
- package/src/core/react-dispatcher.ts +78 -0
- package/src/core/scheduler.ts +1 -1
- package/src/core/types.ts +3 -3
- package/src/hooks/index.ts +12 -0
- package/src/hooks/use.ts +13 -0
- package/src/hooks/useCallback.ts +9 -0
- package/src/hooks/{tap-effect.ts → useEffect.ts} +9 -9
- package/src/hooks/{tap-effect-event.ts → useEffectEvent.ts} +9 -9
- package/src/hooks/{tap-memo.ts → useMemo.ts} +3 -3
- package/src/hooks/useMemoCache.ts +25 -0
- package/src/hooks/{tap-reducer.ts → useReducer.ts} +23 -11
- package/src/hooks/useRef.ts +16 -0
- package/src/hooks/{tap-resource.ts → useResource.ts} +13 -12
- package/src/{tapResourceRoot.ts → hooks/useResourceRoot.ts} +26 -29
- package/src/hooks/{tap-resources.ts → useResources.ts} +21 -22
- package/src/hooks/useState.ts +29 -0
- package/src/hooks/utils/{tapHook.ts → useCell.ts} +1 -1
- package/src/index.ts +4 -24
- package/src/react/hooks.ts +112 -0
- package/src/react-shim/index.ts +64 -0
- package/dist/hooks/tap-callback.d.ts +0 -5
- package/dist/hooks/tap-callback.d.ts.map +0 -1
- package/dist/hooks/tap-callback.js +0 -9
- package/dist/hooks/tap-callback.js.map +0 -1
- package/dist/hooks/tap-const.d.ts +0 -5
- package/dist/hooks/tap-const.d.ts.map +0 -1
- package/dist/hooks/tap-const.js +0 -10
- package/dist/hooks/tap-const.js.map +0 -1
- package/dist/hooks/tap-effect-event.d.ts.map +0 -1
- package/dist/hooks/tap-effect-event.js.map +0 -1
- package/dist/hooks/tap-effect.d.ts +0 -10
- package/dist/hooks/tap-effect.d.ts.map +0 -1
- package/dist/hooks/tap-effect.js.map +0 -1
- package/dist/hooks/tap-memo.d.ts +0 -5
- package/dist/hooks/tap-memo.d.ts.map +0 -1
- package/dist/hooks/tap-memo.js.map +0 -1
- package/dist/hooks/tap-reducer.d.ts +0 -9
- package/dist/hooks/tap-reducer.d.ts.map +0 -1
- package/dist/hooks/tap-reducer.js.map +0 -1
- package/dist/hooks/tap-ref.d.ts +0 -11
- package/dist/hooks/tap-ref.d.ts.map +0 -1
- package/dist/hooks/tap-ref.js +0 -10
- package/dist/hooks/tap-ref.js.map +0 -1
- package/dist/hooks/tap-resource.d.ts +0 -8
- package/dist/hooks/tap-resource.d.ts.map +0 -1
- package/dist/hooks/tap-resource.js.map +0 -1
- package/dist/hooks/tap-resources.d.ts.map +0 -1
- package/dist/hooks/tap-resources.js.map +0 -1
- package/dist/hooks/tap-state.d.ts +0 -9
- package/dist/hooks/tap-state.d.ts.map +0 -1
- package/dist/hooks/tap-state.js +0 -11
- package/dist/hooks/tap-state.js.map +0 -1
- package/dist/hooks/utils/tapHook.d.ts +0 -10
- package/dist/hooks/utils/tapHook.d.ts.map +0 -1
- package/dist/react/index.d.ts +0 -2
- package/dist/react/index.js +0 -2
- package/dist/react/use-resource.d.ts.map +0 -1
- package/dist/react/use-resource.js +0 -46
- package/dist/react/use-resource.js.map +0 -1
- package/dist/tapResourceRoot.d.ts +0 -20
- package/dist/tapResourceRoot.d.ts.map +0 -1
- package/dist/tapResourceRoot.js.map +0 -1
- package/react/package.json +0 -5
- package/src/hooks/tap-callback.ts +0 -9
- package/src/hooks/tap-const.ts +0 -6
- package/src/hooks/tap-ref.ts +0 -16
- package/src/hooks/tap-state.ts +0 -29
- package/src/react/index.ts +0 -1
- package/src/react/use-resource.ts +0 -61
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { useEffect } from "../../hooks/useEffect";
|
|
3
|
+
import { useState } from "../../hooks/useState";
|
|
4
4
|
import { createTestResource, renderTest } from "../test-utils";
|
|
5
5
|
import {
|
|
6
6
|
renderResourceFiber,
|
|
@@ -13,11 +13,11 @@ describe("Rules of Hooks - Hook Order", () => {
|
|
|
13
13
|
|
|
14
14
|
const resource = createTestResource(() => {
|
|
15
15
|
if (condition) {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
useState(1);
|
|
17
|
+
useEffect(() => {}, []);
|
|
18
18
|
} else {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
useEffect(() => {}, []);
|
|
20
|
+
useState(1);
|
|
21
21
|
}
|
|
22
22
|
return null;
|
|
23
23
|
});
|
|
@@ -35,13 +35,13 @@ describe("Rules of Hooks - Hook Order", () => {
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
it("should throw when hook types change between renders", () => {
|
|
38
|
-
let
|
|
38
|
+
let addEffect = false;
|
|
39
39
|
|
|
40
40
|
const resource = createTestResource(() => {
|
|
41
|
-
if (
|
|
42
|
-
|
|
41
|
+
if (addEffect) {
|
|
42
|
+
useEffect(() => {});
|
|
43
43
|
} else {
|
|
44
|
-
|
|
44
|
+
useState(0);
|
|
45
45
|
}
|
|
46
46
|
return null;
|
|
47
47
|
});
|
|
@@ -49,7 +49,7 @@ describe("Rules of Hooks - Hook Order", () => {
|
|
|
49
49
|
renderTest(resource, undefined);
|
|
50
50
|
|
|
51
51
|
// Change to use different hook type
|
|
52
|
-
|
|
52
|
+
addEffect = true;
|
|
53
53
|
|
|
54
54
|
expect(() => renderResourceFiber(resource, undefined)).toThrow(
|
|
55
55
|
"Hook order changed between renders",
|
|
@@ -60,13 +60,13 @@ describe("Rules of Hooks - Hook Order", () => {
|
|
|
60
60
|
let condition = true;
|
|
61
61
|
|
|
62
62
|
const resource = createTestResource(() => {
|
|
63
|
-
|
|
63
|
+
useState(1);
|
|
64
64
|
|
|
65
65
|
if (condition) {
|
|
66
|
-
|
|
66
|
+
useState(2); // Conditional hook
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
useState(3);
|
|
70
70
|
return null;
|
|
71
71
|
});
|
|
72
72
|
|
|
@@ -86,7 +86,7 @@ describe("Rules of Hooks - Hook Order", () => {
|
|
|
86
86
|
|
|
87
87
|
const resource = createTestResource(() => {
|
|
88
88
|
const states = items.map((item) => {
|
|
89
|
-
const [value] =
|
|
89
|
+
const [value] = useState(item);
|
|
90
90
|
return value;
|
|
91
91
|
});
|
|
92
92
|
|
|
@@ -105,7 +105,7 @@ describe("Rules of Hooks - Hook Order", () => {
|
|
|
105
105
|
|
|
106
106
|
const resource = createTestResource(() => {
|
|
107
107
|
items.forEach((item) => {
|
|
108
|
-
|
|
108
|
+
useState(item);
|
|
109
109
|
});
|
|
110
110
|
return null;
|
|
111
111
|
});
|
|
@@ -122,11 +122,11 @@ describe("Rules of Hooks - Hook Order", () => {
|
|
|
122
122
|
|
|
123
123
|
it("should maintain order with mixed hook types", () => {
|
|
124
124
|
const resource = createTestResource(() => {
|
|
125
|
-
const [a] =
|
|
126
|
-
|
|
127
|
-
const [b] =
|
|
128
|
-
|
|
129
|
-
const [c] =
|
|
125
|
+
const [a] = useState(1);
|
|
126
|
+
useEffect(() => {});
|
|
127
|
+
const [b] = useState(2);
|
|
128
|
+
useEffect(() => {});
|
|
129
|
+
const [c] = useState(3);
|
|
130
130
|
|
|
131
131
|
return { a, b, c };
|
|
132
132
|
});
|
|
@@ -143,13 +143,13 @@ describe("Rules of Hooks - Hook Order", () => {
|
|
|
143
143
|
let shouldReturn = false;
|
|
144
144
|
|
|
145
145
|
const resource = createTestResource(() => {
|
|
146
|
-
const [a] =
|
|
146
|
+
const [a] = useState(1);
|
|
147
147
|
|
|
148
148
|
if (shouldReturn) {
|
|
149
149
|
return a; // Early return
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
const [b] =
|
|
152
|
+
const [b] = useState(2);
|
|
153
153
|
return a + b;
|
|
154
154
|
});
|
|
155
155
|
|
|
@@ -166,19 +166,19 @@ describe("Rules of Hooks - Hook Order", () => {
|
|
|
166
166
|
|
|
167
167
|
it("should throw on nested hook calls", () => {
|
|
168
168
|
const resource = createTestResource(() => {
|
|
169
|
-
const [count, setCount] =
|
|
169
|
+
const [count, setCount] = useState(0);
|
|
170
170
|
|
|
171
171
|
// This effect contains a hook call, which is invalid
|
|
172
|
-
|
|
172
|
+
useEffect(() => {
|
|
173
173
|
if (count > 0) {
|
|
174
174
|
expect(() => {
|
|
175
|
-
const [_nested] =
|
|
175
|
+
const [_nested] = useState(0); // Invalid: hook inside effect
|
|
176
176
|
}).toThrow("No resource fiber available");
|
|
177
177
|
}
|
|
178
178
|
});
|
|
179
179
|
|
|
180
180
|
// Use an effect to trigger the state change
|
|
181
|
-
|
|
181
|
+
useEffect(() => {
|
|
182
182
|
if (count === 0) {
|
|
183
183
|
setCount(1);
|
|
184
184
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Tests to verify React's strict mode behavior
|
|
3
3
|
* These tests verify React's own behavior, not tap's implementation
|
|
4
4
|
*/
|
|
5
|
-
/* oxlint-disable
|
|
5
|
+
/* oxlint-disable react/exhaustive-deps -- intentional missing-dep patterns for strict-mode tests */
|
|
6
6
|
|
|
7
7
|
import { describe, it, expect } from "vitest";
|
|
8
8
|
import { render } from "@testing-library/react";
|
|
@@ -712,7 +712,6 @@ describe("React Strict Mode Behavior Verification", () => {
|
|
|
712
712
|
const [count, setCount] = useState(0);
|
|
713
713
|
events.push(`render count=${count}`);
|
|
714
714
|
|
|
715
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: testing strict mode behavior with intentionally incomplete deps
|
|
716
715
|
useEffect(() => {
|
|
717
716
|
effectRunCount++;
|
|
718
717
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
@@ -763,7 +762,6 @@ describe("React Strict Mode Behavior Verification", () => {
|
|
|
763
762
|
const [count, setCount] = useState(0);
|
|
764
763
|
events.push(`render count=${count}`);
|
|
765
764
|
|
|
766
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: testing strict mode behavior with intentionally incomplete deps
|
|
767
765
|
useEffect(() => {
|
|
768
766
|
effectRunCount++;
|
|
769
767
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
@@ -814,7 +812,6 @@ describe("React Strict Mode Behavior Verification", () => {
|
|
|
814
812
|
const [count, setCount] = useState(0);
|
|
815
813
|
events.push(`render count=${count}`);
|
|
816
814
|
|
|
817
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: testing strict mode behavior with intentionally incomplete deps
|
|
818
815
|
useEffect(() => {
|
|
819
816
|
effectRunCount++;
|
|
820
817
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
2
|
import { resource } from "../../core/resource";
|
|
3
3
|
import { isDevelopment } from "../../core/helpers/env";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
4
|
+
import { useRef } from "../../hooks/useRef";
|
|
5
|
+
import { useState } from "../../hooks/useState";
|
|
6
|
+
import { useEffect } from "../../hooks/useEffect";
|
|
7
|
+
import { useMemo } from "../../hooks/useMemo";
|
|
8
|
+
import { useResource } from "../../hooks/useResource";
|
|
9
9
|
import { createResourceRoot } from "../../core/createResourceRoot";
|
|
10
10
|
import { withKey } from "../../core/withKey";
|
|
11
11
|
|
|
@@ -14,16 +14,16 @@ describe("Strict Mode", () => {
|
|
|
14
14
|
expect(isDevelopment).toBe(true);
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it("should persist
|
|
17
|
+
it("should persist useMemo cache across strict mode double render", () => {
|
|
18
18
|
const events: string[] = [];
|
|
19
19
|
let outerCount = 0;
|
|
20
20
|
let memoCount = 0;
|
|
21
21
|
|
|
22
|
-
const TestResource = resource(()
|
|
22
|
+
const TestResource = resource(function TestResource() {
|
|
23
23
|
const idx = outerCount++;
|
|
24
24
|
events.push(`outer-${idx}`);
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
useMemo(() => {
|
|
27
27
|
events.push(`memo-${memoCount++}`);
|
|
28
28
|
return {};
|
|
29
29
|
}, []);
|
|
@@ -36,7 +36,7 @@ describe("Strict Mode", () => {
|
|
|
36
36
|
|
|
37
37
|
console.log("Events:", events);
|
|
38
38
|
|
|
39
|
-
//
|
|
39
|
+
// useMemo factory runs twice during first render (strict mode double-call)
|
|
40
40
|
// but should NOT run during second render (cache should persist)
|
|
41
41
|
expect(events).toEqual([
|
|
42
42
|
"outer-0",
|
|
@@ -49,12 +49,12 @@ describe("Strict Mode", () => {
|
|
|
49
49
|
]);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
it("should double-invoke
|
|
52
|
+
it("should double-invoke useMemo factory and use the first result", () => {
|
|
53
53
|
const events: string[] = [];
|
|
54
54
|
let memoCallCount = 0;
|
|
55
55
|
|
|
56
|
-
const TestResource = resource(()
|
|
57
|
-
const memoValue =
|
|
56
|
+
const TestResource = resource(function TestResource() {
|
|
57
|
+
const memoValue = useMemo(() => {
|
|
58
58
|
memoCallCount++;
|
|
59
59
|
events.push(`memo-${memoCallCount}`);
|
|
60
60
|
return memoCallCount;
|
|
@@ -79,7 +79,7 @@ describe("Strict Mode", () => {
|
|
|
79
79
|
it("should double-render on first render", () => {
|
|
80
80
|
let renderCount = 0;
|
|
81
81
|
|
|
82
|
-
const TestResource = resource(()
|
|
82
|
+
const TestResource = resource(function TestResource() {
|
|
83
83
|
renderCount++;
|
|
84
84
|
return { renderCount };
|
|
85
85
|
});
|
|
@@ -95,13 +95,13 @@ describe("Strict Mode", () => {
|
|
|
95
95
|
it("should double-call hook fns", () => {
|
|
96
96
|
let renderCount = 0;
|
|
97
97
|
|
|
98
|
-
const TestResource = resource(()
|
|
99
|
-
const ref =
|
|
100
|
-
const [count] =
|
|
98
|
+
const TestResource = resource(function TestResource() {
|
|
99
|
+
const ref = useRef(0);
|
|
100
|
+
const [count] = useState(() => {
|
|
101
101
|
renderCount++;
|
|
102
102
|
return ++ref.current;
|
|
103
103
|
});
|
|
104
|
-
const [count2] =
|
|
104
|
+
const [count2] = useState(() => {
|
|
105
105
|
renderCount++;
|
|
106
106
|
return ++ref.current;
|
|
107
107
|
});
|
|
@@ -119,12 +119,12 @@ describe("Strict Mode", () => {
|
|
|
119
119
|
|
|
120
120
|
it("should double-commit effects", () => {
|
|
121
121
|
const events: string[] = [];
|
|
122
|
-
const TestResource = resource(()
|
|
123
|
-
const ref =
|
|
122
|
+
const TestResource = resource(function TestResource() {
|
|
123
|
+
const ref = useRef(0);
|
|
124
124
|
ref.current++;
|
|
125
125
|
const count = ref.current;
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
useEffect(() => {
|
|
128
128
|
events.push("mount-1");
|
|
129
129
|
|
|
130
130
|
return () => {
|
|
@@ -132,7 +132,7 @@ describe("Strict Mode", () => {
|
|
|
132
132
|
};
|
|
133
133
|
});
|
|
134
134
|
|
|
135
|
-
|
|
135
|
+
useEffect(() => {
|
|
136
136
|
events.push("mount-2");
|
|
137
137
|
|
|
138
138
|
return () => {
|
|
@@ -140,7 +140,7 @@ describe("Strict Mode", () => {
|
|
|
140
140
|
};
|
|
141
141
|
}, []);
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
useEffect(() => {
|
|
144
144
|
expect(count).toBe(2);
|
|
145
145
|
|
|
146
146
|
events.push("mount-3");
|
|
@@ -170,13 +170,13 @@ describe("Strict Mode", () => {
|
|
|
170
170
|
it("should double-render on child render", () => {
|
|
171
171
|
let renderCount = 0;
|
|
172
172
|
|
|
173
|
-
const TestChildResource = resource(()
|
|
173
|
+
const TestChildResource = resource(function TestChildResource() {
|
|
174
174
|
renderCount++;
|
|
175
175
|
return { renderCount };
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
-
const TestResource = resource(()
|
|
179
|
-
return
|
|
178
|
+
const TestResource = resource(function TestResource() {
|
|
179
|
+
return useResource(TestChildResource());
|
|
180
180
|
});
|
|
181
181
|
|
|
182
182
|
const root = createResourceRoot();
|
|
@@ -189,10 +189,10 @@ describe("Strict Mode", () => {
|
|
|
189
189
|
|
|
190
190
|
it("should double-mount before handling state updates", () => {
|
|
191
191
|
const events: string[] = [];
|
|
192
|
-
const TestResource = resource(()
|
|
193
|
-
const [id, setId] =
|
|
192
|
+
const TestResource = resource(function TestResource() {
|
|
193
|
+
const [id, setId] = useState(0);
|
|
194
194
|
events.push(`render-${id}`);
|
|
195
|
-
|
|
195
|
+
useEffect(() => {
|
|
196
196
|
events.push(`mount-${id}`);
|
|
197
197
|
setId(1);
|
|
198
198
|
return () => {
|
|
@@ -228,13 +228,13 @@ describe("Strict Mode", () => {
|
|
|
228
228
|
return renderCount;
|
|
229
229
|
};
|
|
230
230
|
|
|
231
|
-
const TestChildResource = resource(()
|
|
232
|
-
const [fnState] =
|
|
231
|
+
const TestChildResource = resource(function TestChildResource() {
|
|
232
|
+
const [fnState] = useState(() => {
|
|
233
233
|
fnCount++;
|
|
234
234
|
return fnCount;
|
|
235
235
|
});
|
|
236
236
|
const count = incrementRenderCount();
|
|
237
|
-
|
|
237
|
+
useEffect(() => {
|
|
238
238
|
expect(fnState % 2).toBe(1);
|
|
239
239
|
expect(count).toBe(fnState + 1);
|
|
240
240
|
|
|
@@ -246,12 +246,12 @@ describe("Strict Mode", () => {
|
|
|
246
246
|
return { renderCount, fnCount, fnState };
|
|
247
247
|
});
|
|
248
248
|
|
|
249
|
-
const TestResource = resource(()
|
|
250
|
-
const [id, setId] =
|
|
251
|
-
|
|
249
|
+
const TestResource = resource(function TestResource() {
|
|
250
|
+
const [id, setId] = useState(0);
|
|
251
|
+
useEffect(() => {
|
|
252
252
|
setId(1);
|
|
253
253
|
});
|
|
254
|
-
return
|
|
254
|
+
return useResource(withKey(id, TestChildResource()));
|
|
255
255
|
});
|
|
256
256
|
|
|
257
257
|
const root = createResourceRoot();
|
|
@@ -270,16 +270,16 @@ describe("Strict Mode", () => {
|
|
|
270
270
|
it("should double-render on child render change", () => {
|
|
271
271
|
let renderCount = 0;
|
|
272
272
|
const events: string[] = [];
|
|
273
|
-
const TestChildResource = resource(()
|
|
273
|
+
const TestChildResource = resource(function TestChildResource() {
|
|
274
274
|
renderCount++;
|
|
275
275
|
events.push(`render-${renderCount}`);
|
|
276
276
|
|
|
277
|
-
|
|
277
|
+
useState(() => {
|
|
278
278
|
return events.push(`fn-${renderCount}`);
|
|
279
279
|
});
|
|
280
280
|
|
|
281
281
|
const count = renderCount;
|
|
282
|
-
|
|
282
|
+
useEffect(() => {
|
|
283
283
|
events.push(`mount-${count}`);
|
|
284
284
|
return () => {
|
|
285
285
|
events.push(`unmount-${count}`);
|
|
@@ -287,10 +287,10 @@ describe("Strict Mode", () => {
|
|
|
287
287
|
});
|
|
288
288
|
});
|
|
289
289
|
|
|
290
|
-
const TestResource = resource(()
|
|
291
|
-
const [id, setId] =
|
|
290
|
+
const TestResource = resource(function TestResource() {
|
|
291
|
+
const [id, setId] = useState(0);
|
|
292
292
|
events.push(`outer-render-${id}`);
|
|
293
|
-
|
|
293
|
+
useEffect(() => {
|
|
294
294
|
events.push(`outer-mount-${id}`);
|
|
295
295
|
setId(1);
|
|
296
296
|
|
|
@@ -298,7 +298,7 @@ describe("Strict Mode", () => {
|
|
|
298
298
|
events.push(`outer-unmount-${id}`);
|
|
299
299
|
};
|
|
300
300
|
});
|
|
301
|
-
return
|
|
301
|
+
return useResource(withKey(id, TestChildResource()));
|
|
302
302
|
});
|
|
303
303
|
|
|
304
304
|
const root = createResourceRoot();
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Tests to verify when tap strict mode causes double-rendering
|
|
3
3
|
* These tests should mirror the React strict mode behavior
|
|
4
4
|
*/
|
|
5
|
-
/* oxlint-disable
|
|
5
|
+
/* oxlint-disable react/exhaustive-deps -- empty dep arrays are part of the test scenarios */
|
|
6
6
|
|
|
7
7
|
import { afterEach, describe, it, expect, vi } from "vitest";
|
|
8
8
|
import { resource } from "../../core/resource";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { useState } from "../../hooks/useState";
|
|
10
|
+
import { useEffect } from "../../hooks/useEffect";
|
|
11
11
|
import { createResourceRoot } from "../../core/createResourceRoot";
|
|
12
12
|
import { flushResourcesSync } from "../../core/scheduler";
|
|
13
13
|
|
|
@@ -17,11 +17,11 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
17
17
|
const events: string[] = [];
|
|
18
18
|
let updaterCallCount = 0;
|
|
19
19
|
|
|
20
|
-
const TestResource = resource(()
|
|
21
|
-
const [count, setCount] =
|
|
20
|
+
const TestResource = resource(function TestResource() {
|
|
21
|
+
const [count, setCount] = useState(0);
|
|
22
22
|
events.push(`render count=${count}`);
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
useEffect(() => {
|
|
25
25
|
events.push("effect mount");
|
|
26
26
|
setCount((prev) => {
|
|
27
27
|
updaterCallCount++;
|
|
@@ -70,8 +70,8 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
70
70
|
it("should double-render on initial mount", () => {
|
|
71
71
|
const events: string[] = [];
|
|
72
72
|
|
|
73
|
-
const TestResource = resource(()
|
|
74
|
-
const [count] =
|
|
73
|
+
const TestResource = resource(function TestResource() {
|
|
74
|
+
const [count] = useState(0);
|
|
75
75
|
events.push(`render count=${count}`);
|
|
76
76
|
return { count };
|
|
77
77
|
});
|
|
@@ -83,15 +83,15 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
83
83
|
});
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
describe("Source 2: setState in
|
|
87
|
-
it("should double-render after setState in
|
|
86
|
+
describe("Source 2: setState in useEffect", () => {
|
|
87
|
+
it("should double-render after setState in useEffect", () => {
|
|
88
88
|
const events: string[] = [];
|
|
89
89
|
|
|
90
|
-
const TestResource = resource(()
|
|
91
|
-
const [count, setCount] =
|
|
90
|
+
const TestResource = resource(function TestResource() {
|
|
91
|
+
const [count, setCount] = useState(0);
|
|
92
92
|
events.push(`render count=${count}`);
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
useEffect(() => {
|
|
95
95
|
events.push(`effect count=${count}`);
|
|
96
96
|
if (count === 0) {
|
|
97
97
|
setCount(1);
|
|
@@ -125,8 +125,8 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
125
125
|
it("should ALSO double-render after setState in flushResourcesSync", () => {
|
|
126
126
|
const events: string[] = [];
|
|
127
127
|
|
|
128
|
-
const TestResource = resource(()
|
|
129
|
-
const [count, setCount] =
|
|
128
|
+
const TestResource = resource(function TestResource() {
|
|
129
|
+
const [count, setCount] = useState(0);
|
|
130
130
|
events.push(`render count=${count}`);
|
|
131
131
|
|
|
132
132
|
return {
|
|
@@ -158,8 +158,8 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
158
158
|
it("should double-render on ALL flushResourcesSync calls", () => {
|
|
159
159
|
const events: string[] = [];
|
|
160
160
|
|
|
161
|
-
const TestResource = resource(()
|
|
162
|
-
const [count, setCount] =
|
|
161
|
+
const TestResource = resource(function TestResource() {
|
|
162
|
+
const [count, setCount] = useState(0);
|
|
163
163
|
events.push(`render count=${count}`);
|
|
164
164
|
|
|
165
165
|
return {
|
|
@@ -212,11 +212,11 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
212
212
|
|
|
213
213
|
const events: string[] = [];
|
|
214
214
|
|
|
215
|
-
const TestResource = resource(()
|
|
216
|
-
const [count, setCount] =
|
|
215
|
+
const TestResource = resource(function TestResource() {
|
|
216
|
+
const [count, setCount] = useState(0);
|
|
217
217
|
events.push(`render count=${count}`);
|
|
218
218
|
|
|
219
|
-
|
|
219
|
+
useEffect(() => {
|
|
220
220
|
if (count === 0) {
|
|
221
221
|
setTimeout(() => {
|
|
222
222
|
events.push("setTimeout");
|
|
@@ -253,11 +253,11 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
253
253
|
it("should double-render AND double-call Promise callback", async () => {
|
|
254
254
|
const events: string[] = [];
|
|
255
255
|
|
|
256
|
-
const TestResource = resource(()
|
|
257
|
-
const [count, setCount] =
|
|
256
|
+
const TestResource = resource(function TestResource() {
|
|
257
|
+
const [count, setCount] = useState(0);
|
|
258
258
|
events.push(`render count=${count}`);
|
|
259
259
|
|
|
260
|
-
|
|
260
|
+
useEffect(() => {
|
|
261
261
|
if (count === 0) {
|
|
262
262
|
Promise.resolve().then(() => {
|
|
263
263
|
events.push("promise");
|
|
@@ -291,9 +291,9 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
291
291
|
it("should batch multiple setState calls in flushResourcesSync (single double-render)", () => {
|
|
292
292
|
const events: string[] = [];
|
|
293
293
|
|
|
294
|
-
const TestResource = resource(()
|
|
295
|
-
const [count1, setCount1] =
|
|
296
|
-
const [count2, setCount2] =
|
|
294
|
+
const TestResource = resource(function TestResource() {
|
|
295
|
+
const [count1, setCount1] = useState(0);
|
|
296
|
+
const [count2, setCount2] = useState(0);
|
|
297
297
|
events.push(`render count1=${count1} count2=${count2}`);
|
|
298
298
|
|
|
299
299
|
return {
|
|
@@ -322,15 +322,15 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
322
322
|
]);
|
|
323
323
|
});
|
|
324
324
|
|
|
325
|
-
it("should batch multiple setState calls in
|
|
325
|
+
it("should batch multiple setState calls in useEffect (single double-render)", () => {
|
|
326
326
|
const events: string[] = [];
|
|
327
327
|
|
|
328
|
-
const TestResource = resource(()
|
|
329
|
-
const [count1, setCount1] =
|
|
330
|
-
const [count2, setCount2] =
|
|
328
|
+
const TestResource = resource(function TestResource() {
|
|
329
|
+
const [count1, setCount1] = useState(0);
|
|
330
|
+
const [count2, setCount2] = useState(0);
|
|
331
331
|
events.push(`render count1=${count1} count2=${count2}`);
|
|
332
332
|
|
|
333
|
-
|
|
333
|
+
useEffect(() => {
|
|
334
334
|
if (count1 === 0 && count2 === 0) {
|
|
335
335
|
setCount1(1);
|
|
336
336
|
setCount2(2);
|
|
@@ -357,8 +357,8 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
357
357
|
it("should double-render simple resources", () => {
|
|
358
358
|
const events: string[] = [];
|
|
359
359
|
|
|
360
|
-
const TestResource = resource(()
|
|
361
|
-
const [count, setCount] =
|
|
360
|
+
const TestResource = resource(function TestResource() {
|
|
361
|
+
const [count, setCount] = useState(0);
|
|
362
362
|
events.push(`render count=${count}`);
|
|
363
363
|
|
|
364
364
|
return {
|
|
@@ -379,8 +379,8 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
379
379
|
it("should double-render with function updater in flushResourcesSync", () => {
|
|
380
380
|
const events: string[] = [];
|
|
381
381
|
|
|
382
|
-
const TestResource = resource(()
|
|
383
|
-
const [count, setCount] =
|
|
382
|
+
const TestResource = resource(function TestResource() {
|
|
383
|
+
const [count, setCount] = useState(0);
|
|
384
384
|
events.push(`render count=${count}`);
|
|
385
385
|
|
|
386
386
|
return {
|
|
@@ -419,12 +419,12 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
419
419
|
it("should handle effect with dependencies and setState", () => {
|
|
420
420
|
const events: string[] = [];
|
|
421
421
|
|
|
422
|
-
const TestResource = resource(()
|
|
423
|
-
const [count, setCount] =
|
|
424
|
-
const [doubled, setDoubled] =
|
|
422
|
+
const TestResource = resource(function TestResource() {
|
|
423
|
+
const [count, setCount] = useState(0);
|
|
424
|
+
const [doubled, setDoubled] = useState(0);
|
|
425
425
|
events.push(`render count=${count} doubled=${doubled}`);
|
|
426
426
|
|
|
427
|
-
|
|
427
|
+
useEffect(() => {
|
|
428
428
|
events.push(`effect count=${count}`);
|
|
429
429
|
setDoubled(count * 2);
|
|
430
430
|
return () => {
|
|
@@ -469,13 +469,13 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
469
469
|
});
|
|
470
470
|
});
|
|
471
471
|
|
|
472
|
-
describe("Source 10:
|
|
473
|
-
it("should call
|
|
472
|
+
describe("Source 10: useState initializer function", () => {
|
|
473
|
+
it("should call useState initializer twice", () => {
|
|
474
474
|
const events: string[] = [];
|
|
475
475
|
let initCount = 0;
|
|
476
476
|
|
|
477
|
-
const TestResource = resource(()
|
|
478
|
-
const [value] =
|
|
477
|
+
const TestResource = resource(function TestResource() {
|
|
478
|
+
const [value] = useState(() => {
|
|
479
479
|
initCount++;
|
|
480
480
|
events.push(`init call #${initCount}`);
|
|
481
481
|
return initCount;
|
|
@@ -489,7 +489,7 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
489
489
|
const root = createResourceRoot();
|
|
490
490
|
root.render(TestResource());
|
|
491
491
|
|
|
492
|
-
//
|
|
492
|
+
// useState initializer should be called twice, first value kept
|
|
493
493
|
expect(events).toEqual([
|
|
494
494
|
"init call #1",
|
|
495
495
|
"init call #2",
|
|
@@ -503,8 +503,8 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
503
503
|
it("should maintain double-render behavior after disposal and recreation", () => {
|
|
504
504
|
const events: string[] = [];
|
|
505
505
|
|
|
506
|
-
const TestResource = resource(()
|
|
507
|
-
const [count, setCount] =
|
|
506
|
+
const TestResource = resource(function TestResource() {
|
|
507
|
+
const [count, setCount] = useState(0);
|
|
508
508
|
events.push(`render count=${count}`);
|
|
509
509
|
|
|
510
510
|
return {
|
|
@@ -547,12 +547,11 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
547
547
|
const events: string[] = [];
|
|
548
548
|
let effectRunCount = 0;
|
|
549
549
|
|
|
550
|
-
const TestResource = resource(()
|
|
551
|
-
const [count, setCount] =
|
|
550
|
+
const TestResource = resource(function TestResource() {
|
|
551
|
+
const [count, setCount] = useState(0);
|
|
552
552
|
events.push(`render count=${count}`);
|
|
553
553
|
|
|
554
|
-
|
|
555
|
-
tapEffect(() => {
|
|
554
|
+
useEffect(() => {
|
|
556
555
|
effectRunCount++;
|
|
557
556
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
558
557
|
|
|
@@ -594,12 +593,11 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
594
593
|
const events: string[] = [];
|
|
595
594
|
let effectRunCount = 0;
|
|
596
595
|
|
|
597
|
-
const TestResource = resource(()
|
|
598
|
-
const [count, setCount] =
|
|
596
|
+
const TestResource = resource(function TestResource() {
|
|
597
|
+
const [count, setCount] = useState(0);
|
|
599
598
|
events.push(`render count=${count}`);
|
|
600
599
|
|
|
601
|
-
|
|
602
|
-
tapEffect(() => {
|
|
600
|
+
useEffect(() => {
|
|
603
601
|
effectRunCount++;
|
|
604
602
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
605
603
|
|
|
@@ -640,12 +638,11 @@ describe("Tap Strict Mode - Rerender Sources", () => {
|
|
|
640
638
|
const events: string[] = [];
|
|
641
639
|
let effectRunCount = 0;
|
|
642
640
|
|
|
643
|
-
const TestResource = resource(()
|
|
644
|
-
const [count, setCount] =
|
|
641
|
+
const TestResource = resource(function TestResource() {
|
|
642
|
+
const [count, setCount] = useState(0);
|
|
645
643
|
events.push(`render count=${count}`);
|
|
646
644
|
|
|
647
|
-
|
|
648
|
-
tapEffect(() => {
|
|
645
|
+
useEffect(() => {
|
|
649
646
|
effectRunCount++;
|
|
650
647
|
events.push(`effect mount #${effectRunCount} count=${count}`);
|
|
651
648
|
|