diff --git a/.changeset/afraid-places-act.md b/.changeset/afraid-places-act.md
new file mode 100644
index 0000000000..8872906118
--- /dev/null
+++ b/.changeset/afraid-places-act.md
@@ -0,0 +1,5 @@
+---
+"@lynx-js/react": minor
+---
+
+refactor: create SnapshotInstance in renderToString directly
diff --git a/packages/react/runtime/__test__/lifecycle/reload.test.jsx b/packages/react/runtime/__test__/lifecycle/reload.test.jsx
index c9e5cfbb7c..22bb645e80 100644
--- a/packages/react/runtime/__test__/lifecycle/reload.test.jsx
+++ b/packages/react/runtime/__test__/lifecycle/reload.test.jsx
@@ -123,7 +123,7 @@ describe('reload', () => {
expect(lynx.getNativeApp().callLepusMethod).toHaveBeenCalledTimes(1);
expect(lynx.getNativeApp().callLepusMethod.mock.calls[0][1]).toMatchInlineSnapshot(`
{
- "data": "{"patchList":[{"id":3,"snapshotPatch":[3,-5,0,{"dataX2":"WorldX2"},3,-8,0,"update",3,-6,0,{"attr":{"dataX2":"WorldX2"}}]}]}",
+ "data": "{"patchList":[{"id":3,"snapshotPatch":[3,-5,0,{"dataX2":"WorldX2"},3,-7,0,"update",3,-8,0,{"attr":{"dataX2":"WorldX2"}}]}]}",
"patchOptions": {
"flowIds": [
666,
@@ -234,7 +234,7 @@ describe('reload', () => {
expect(lynx.getNativeApp().callLepusMethod).toHaveBeenCalledTimes(1);
expect(lynx.getNativeApp().callLepusMethod.mock.calls[0][1]).toMatchInlineSnapshot(`
{
- "data": "{"patchList":[{"id":4,"snapshotPatch":[3,-8,0,"???"]}]}",
+ "data": "{"patchList":[{"id":4,"snapshotPatch":[3,-7,0,"???"]}]}",
"patchOptions": {
"flowIds": [
666,
@@ -305,7 +305,7 @@ describe('reload', () => {
[
"rLynxFirstScreen",
{
- "root": "{"id":-9,"type":"root","children":[{"id":-13,"type":"__snapshot_a94a8_test_2","values":[{"dataX":"WorldX"}],"children":[{"id":-10,"type":"__snapshot_a94a8_test_3","children":[{"id":-15,"type":null,"values":["Enjoy"]}]},{"id":-11,"type":"__snapshot_a94a8_test_4","children":[{"id":-16,"type":null,"values":["World"]}]},{"id":-12,"type":"wrapper","children":[{"id":-14,"type":"__snapshot_a94a8_test_1","values":[{"attr":{"dataX":"WorldX"}}]}]}]}]}",
+ "root": "{"id":-9,"type":"root","children":[{"id":-13,"type":"__snapshot_a94a8_test_2","values":[{"dataX":"WorldX"}],"children":[{"id":-10,"type":"__snapshot_a94a8_test_3","children":[{"id":-14,"type":null,"values":["Enjoy"]}]},{"id":-11,"type":"__snapshot_a94a8_test_4","children":[{"id":-15,"type":null,"values":["World"]}]},{"id":-12,"type":"wrapper","children":[{"id":-16,"type":"__snapshot_a94a8_test_1","values":[{"attr":{"dataX":"WorldX"}}]}]}]}]}",
},
],
],
@@ -386,7 +386,7 @@ describe('reload', () => {
expect(lynx.getNativeApp().callLepusMethod).toHaveBeenCalledTimes(1);
expect(lynx.getNativeApp().callLepusMethod.mock.calls[0][1]).toMatchInlineSnapshot(`
{
- "data": "{"patchList":[{"id":8,"snapshotPatch":[3,-16,0,"update"]}]}",
+ "data": "{"patchList":[{"id":8,"snapshotPatch":[3,-15,0,"update"]}]}",
"patchOptions": {
"flowIds": [
666,
@@ -535,7 +535,7 @@ describe('reload', () => {
expect(lynx.getNativeApp().callLepusMethod).toHaveBeenCalledTimes(1);
expect(lynx.getNativeApp().callLepusMethod.mock.calls[0][1]).toMatchInlineSnapshot(`
{
- "data": "{"patchList":[{"id":11,"snapshotPatch":[3,-5,0,{"dataX2":"WorldX2"},3,-8,0,"update",3,-6,0,{"attr":{"dataX2":"WorldX2"}}]}]}",
+ "data": "{"patchList":[{"id":11,"snapshotPatch":[3,-5,0,{"dataX2":"WorldX2"},3,-7,0,"update",3,-8,0,{"attr":{"dataX2":"WorldX2"}}]}]}",
"patchOptions": {
"flowIds": [
666,
@@ -650,7 +650,7 @@ describe('reload', () => {
expect(lynx.getNativeApp().callLepusMethod).toHaveBeenCalledTimes(1);
expect(lynx.getNativeApp().callLepusMethod.mock.calls[0][1]).toMatchInlineSnapshot(`
{
- "data": "{"patchList":[{"id":12,"snapshotPatch":[3,-8,0,"???"]}]}",
+ "data": "{"patchList":[{"id":12,"snapshotPatch":[3,-7,0,"???"]}]}",
"patchOptions": {
"flowIds": [
666,
@@ -723,7 +723,7 @@ describe('reload', () => {
[
"rLynxFirstScreen",
{
- "root": "{"id":-9,"type":"root","children":[{"id":-15,"type":"__snapshot_a94a8_test_5","children":[{"id":-13,"type":"__snapshot_a94a8_test_2","values":[{"dataX":"WorldX"}],"children":[{"id":-10,"type":"__snapshot_a94a8_test_3","children":[{"id":-16,"type":null,"values":["Enjoy"]}]},{"id":-11,"type":"__snapshot_a94a8_test_4","children":[{"id":-17,"type":null,"values":["World"]}]},{"id":-12,"type":"wrapper","children":[{"id":-14,"type":"__snapshot_a94a8_test_1","values":[{"attr":{"dataX":"WorldX"}}]}]}]}]}]}",
+ "root": "{"id":-9,"type":"root","children":[{"id":-10,"type":"__snapshot_a94a8_test_5","children":[{"id":-14,"type":"__snapshot_a94a8_test_2","values":[{"dataX":"WorldX"}],"children":[{"id":-11,"type":"__snapshot_a94a8_test_3","children":[{"id":-15,"type":null,"values":["Enjoy"]}]},{"id":-12,"type":"__snapshot_a94a8_test_4","children":[{"id":-16,"type":null,"values":["World"]}]},{"id":-13,"type":"wrapper","children":[{"id":-17,"type":"__snapshot_a94a8_test_1","values":[{"attr":{"dataX":"WorldX"}}]}]}]}]}]}",
},
],
],
@@ -806,7 +806,7 @@ describe('reload', () => {
expect(lynx.getNativeApp().callLepusMethod).toHaveBeenCalledTimes(1);
expect(lynx.getNativeApp().callLepusMethod.mock.calls[0][1]).toMatchInlineSnapshot(`
{
- "data": "{"patchList":[{"id":16,"snapshotPatch":[3,-17,0,"update"]}]}",
+ "data": "{"patchList":[{"id":16,"snapshotPatch":[3,-16,0,"update"]}]}",
"patchOptions": {
"flowIds": [
666,
@@ -1314,7 +1314,7 @@ describe('firstScreenSyncTiming - jsReady', () => {
"-8": -16,
"-9": -17,
},
- "root": "{"id":-17,"type":"root","children":[{"id":-21,"type":"__snapshot_a94a8_test_2","values":[{"dataX":"WorldX"}],"children":[{"id":-18,"type":"__snapshot_a94a8_test_3","children":[{"id":-23,"type":null,"values":["Hello 2"]}]},{"id":-19,"type":"__snapshot_a94a8_test_4","children":[{"id":-24,"type":null,"values":["World"]}]},{"id":-20,"type":"wrapper","children":[{"id":-22,"type":"__snapshot_a94a8_test_1","values":[{"attr":{"dataX":"WorldX"}}]}]}]}]}",
+ "root": "{"id":-17,"type":"root","children":[{"id":-21,"type":"__snapshot_a94a8_test_2","values":[{"dataX":"WorldX"}],"children":[{"id":-18,"type":"__snapshot_a94a8_test_3","children":[{"id":-22,"type":null,"values":["Hello 2"]}]},{"id":-19,"type":"__snapshot_a94a8_test_4","children":[{"id":-23,"type":null,"values":["World"]}]},{"id":-20,"type":"wrapper","children":[{"id":-24,"type":"__snapshot_a94a8_test_1","values":[{"attr":{"dataX":"WorldX"}}]}]}]}]}",
},
],
]
@@ -1874,7 +1874,7 @@ describe('firstScreenSyncTiming - jsReady', () => {
"rLynxFirstScreen",
{
"jsReadyEventIdSwap": {},
- "root": "{"id":-17,"type":"root","children":[{"id":-21,"type":"__snapshot_a94a8_test_2","values":[{"dataX":"WorldX"}],"children":[{"id":-18,"type":"__snapshot_a94a8_test_3","children":[{"id":-23,"type":null,"values":["Hello 2"]}]},{"id":-19,"type":"__snapshot_a94a8_test_4","children":[{"id":-24,"type":null,"values":["World"]}]},{"id":-20,"type":"wrapper","children":[{"id":-22,"type":"__snapshot_a94a8_test_1","values":[{"attr":{"dataX":"WorldX"}}]}]}]}]}",
+ "root": "{"id":-17,"type":"root","children":[{"id":-21,"type":"__snapshot_a94a8_test_2","values":[{"dataX":"WorldX"}],"children":[{"id":-18,"type":"__snapshot_a94a8_test_3","children":[{"id":-22,"type":null,"values":["Hello 2"]}]},{"id":-19,"type":"__snapshot_a94a8_test_4","children":[{"id":-23,"type":null,"values":["World"]}]},{"id":-20,"type":"wrapper","children":[{"id":-24,"type":"__snapshot_a94a8_test_1","values":[{"attr":{"dataX":"WorldX"}}]}]}]}]}",
},
],
]
diff --git a/packages/react/runtime/__test__/lifecycle/updateData.test.jsx b/packages/react/runtime/__test__/lifecycle/updateData.test.jsx
index 6e5f9cd022..d83897fd43 100644
--- a/packages/react/runtime/__test__/lifecycle/updateData.test.jsx
+++ b/packages/react/runtime/__test__/lifecycle/updateData.test.jsx
@@ -292,7 +292,7 @@ describe('triggerDataUpdated', () => {
[
"rLynxChange",
{
- "data": "{"patchList":[{"id":7,"snapshotPatch":[3,-7,0,"update"]}]}",
+ "data": "{"patchList":[{"id":7,"snapshotPatch":[3,-6,0,"update"]}]}",
"patchOptions": {
"flowIds": [
666,
@@ -528,7 +528,7 @@ describe('triggerDataUpdated', () => {
[
"rLynxChange",
{
- "data": "{"patchList":[{"id":15,"snapshotPatch":[3,-6,0,"update"]}]}",
+ "data": "{"patchList":[{"id":15,"snapshotPatch":[3,-5,0,"update"]}]}",
"patchOptions": {
"reloadVersion": 0,
},
diff --git a/packages/react/runtime/__test__/lynx/suspense.test.jsx b/packages/react/runtime/__test__/lynx/suspense.test.jsx
index 3d7d2d9619..0ec90aff46 100644
--- a/packages/react/runtime/__test__/lynx/suspense.test.jsx
+++ b/packages/react/runtime/__test__/lynx/suspense.test.jsx
@@ -384,9 +384,8 @@ describe('suspense', () => {
expect([...snapshotInstanceManager.values.keys()]).toMatchInlineSnapshot(`
[
-1,
- -2,
-3,
- -4,
+ -5,
]
`);
}
@@ -486,7 +485,6 @@ describe('suspense', () => {
expect([...snapshotInstanceManager.values.keys()]).toMatchInlineSnapshot(`
[
-1,
- -2,
]
`);
@@ -1590,7 +1588,7 @@ describe('suspense', () => {
.toMatchInlineSnapshot(`
[
{
- "childId": -4,
+ "childId": -2,
"op": "RemoveChild",
"parentId": -1,
},
diff --git a/packages/react/runtime/__test__/renderToOpcodes.test.jsx b/packages/react/runtime/__test__/renderToOpcodes.test.jsx
index 99702fe5d9..7de60a1ace 100644
--- a/packages/react/runtime/__test__/renderToOpcodes.test.jsx
+++ b/packages/react/runtime/__test__/renderToOpcodes.test.jsx
@@ -7,21 +7,33 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vite
import { elementTree, waitSchedule } from './utils/nativeMethod';
import { globalEnvManager } from './utils/envManager';
import { setupDocument } from '../src/document';
-import { renderOpcodesInto } from '../src/opcodes';
-import renderToString from '../src/renderToOpcodes';
+// import { renderOpcodesInto } from '../src/opcodes';
+import renderToStringBase from '../src/renderToOpcodes';
import { setupPage, SnapshotInstance, snapshotInstanceManager } from '../src/snapshot';
import { createElement, cloneElement } from '../lepus';
import { Suspense } from 'preact/compat';
import { createSuspender } from './createSuspender';
import { __root } from '../src/root';
-describe('renderToOpcodes', () => {
+const renderToString = (element, root = __root) => {
+ return renderToStringBase(element, null, root);
+};
+
+describe('renderToString', () => {
beforeAll(() => {
globalEnvManager.switchToMainThread();
});
+ beforeEach(() => {
+ setupPage(__CreatePage('0', 0));
+ });
+
afterEach(() => {
vi.clearAllMocks();
+
+ globalEnvManager.resetEnv();
+ elementTree.clear();
+ snapshotInstanceManager.clear();
});
it('should render hello world', () => {
@@ -39,11 +51,23 @@ describe('renderToOpcodes', () => {
[
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -4,
+ "type": null,
+ "values": [
+ "hello world",
+ ],
+ },
+ ],
"extraProps": undefined,
"id": -3,
"type": "__snapshot_a94a8_test_1",
- "values": undefined,
+ "values": [
+ "a",
+ ],
},
2,
"values",
@@ -51,7 +75,18 @@ describe('renderToOpcodes', () => {
"a",
],
3,
- "hello world",
+ [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -4,
+ "type": null,
+ "values": [
+ "hello world",
+ ],
+ },
+ "hello world",
+ ],
1,
]
`);
@@ -77,22 +112,61 @@ describe('renderToOpcodes', () => {
[
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -5,
+ "type": null,
+ "values": [
+ 1000,
+ ],
+ },
+ ],
+ "extraProps": undefined,
+ "id": -4,
+ "type": "__snapshot_a94a8_test_2",
+ "values": undefined,
+ },
+ ],
"extraProps": undefined,
- "id": -4,
+ "id": -2,
"type": "__snapshot_a94a8_test_3",
"values": undefined,
},
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -5,
+ "type": null,
+ "values": [
+ 1000,
+ ],
+ },
+ ],
"extraProps": undefined,
- "id": -6,
+ "id": -4,
"type": "__snapshot_a94a8_test_2",
"values": undefined,
},
3,
- 1000,
+ [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -5,
+ "type": null,
+ "values": [
+ 1000,
+ ],
+ },
+ 1000,
+ ],
1,
1,
]
@@ -121,22 +195,61 @@ describe('renderToOpcodes', () => {
[
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -4,
+ "type": null,
+ "values": [
+ 1,
+ ],
+ },
+ ],
+ "extraProps": undefined,
+ "id": -3,
+ "type": "__snapshot_a94a8_test_4",
+ "values": undefined,
+ },
+ ],
"extraProps": undefined,
- "id": -7,
+ "id": -2,
"type": "__snapshot_a94a8_test_5",
"values": undefined,
},
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -4,
+ "type": null,
+ "values": [
+ 1,
+ ],
+ },
+ ],
"extraProps": undefined,
- "id": -8,
+ "id": -3,
"type": "__snapshot_a94a8_test_4",
"values": undefined,
},
3,
- 1,
+ [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -4,
+ "type": null,
+ "values": [
+ 1,
+ ],
+ },
+ 1,
+ ],
1,
1,
]
@@ -161,9 +274,12 @@ describe('renderToOpcodes', () => {
{
"children": undefined,
"extraProps": undefined,
- "id": -9,
+ "id": -2,
"type": "__snapshot_a94a8_test_6",
- "values": undefined,
+ "values": [
+ ${random},
+ "hello world",
+ ],
},
2,
"values",
@@ -190,14 +306,35 @@ describe('renderToOpcodes', () => {
[
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -3,
+ "type": null,
+ "values": [
+ "111",
+ ],
+ },
+ ],
"extraProps": undefined,
- "id": -10,
+ "id": -2,
"type": "__snapshot_a94a8_test_7",
"values": undefined,
},
3,
- "111",
+ [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -3,
+ "type": null,
+ "values": [
+ "111",
+ ],
+ },
+ "111",
+ ],
1,
]
`);
@@ -219,14 +356,35 @@ describe('renderToOpcodes', () => {
[
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -3,
+ "type": null,
+ "values": [
+ "111",
+ ],
+ },
+ ],
"extraProps": undefined,
- "id": -11,
+ "id": -2,
"type": "__snapshot_a94a8_test_8",
"values": undefined,
},
3,
- "111",
+ [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -3,
+ "type": null,
+ "values": [
+ "111",
+ ],
+ },
+ "111",
+ ],
1,
]
`);
@@ -246,14 +404,35 @@ describe('renderToOpcodes', () => {
[
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -3,
+ "type": null,
+ "values": [
+ "111",
+ ],
+ },
+ ],
"extraProps": undefined,
- "id": -12,
+ "id": -2,
"type": "__snapshot_a94a8_test_9",
"values": undefined,
},
3,
- "111",
+ [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -3,
+ "type": null,
+ "values": [
+ "111",
+ ],
+ },
+ "111",
+ ],
1,
]
`);
@@ -272,22 +451,61 @@ describe('renderToOpcodes', () => {
[
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -4,
+ "type": null,
+ "values": [
+ 11111,
+ ],
+ },
+ ],
+ "extraProps": undefined,
+ "id": -3,
+ "type": "__snapshot_a94a8_test_11",
+ "values": undefined,
+ },
+ ],
"extraProps": undefined,
- "id": -13,
+ "id": -2,
"type": "__snapshot_a94a8_test_10",
"values": undefined,
},
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -4,
+ "type": null,
+ "values": [
+ 11111,
+ ],
+ },
+ ],
"extraProps": undefined,
- "id": -14,
+ "id": -3,
"type": "__snapshot_a94a8_test_11",
"values": undefined,
},
3,
- 11111,
+ [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -4,
+ "type": null,
+ "values": [
+ 11111,
+ ],
+ },
+ 11111,
+ ],
1,
1,
]
@@ -306,22 +524,61 @@ describe('renderToOpcodes', () => {
[
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -7,
+ "type": null,
+ "values": [
+ 12345,
+ ],
+ },
+ ],
+ "extraProps": undefined,
+ "id": -6,
+ "type": "__snapshot_a94a8_test_13",
+ "values": undefined,
+ },
+ ],
"extraProps": undefined,
- "id": -15,
+ "id": -5,
"type": "__snapshot_a94a8_test_12",
"values": undefined,
},
0,
{
- "children": undefined,
+ "children": [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -7,
+ "type": null,
+ "values": [
+ 12345,
+ ],
+ },
+ ],
"extraProps": undefined,
- "id": -16,
+ "id": -6,
"type": "__snapshot_a94a8_test_13",
"values": undefined,
},
3,
- 12345,
+ [
+ {
+ "children": undefined,
+ "extraProps": undefined,
+ "id": -7,
+ "type": null,
+ "values": [
+ 12345,
+ ],
+ },
+ 12345,
+ ],
1,
1,
]
@@ -618,13 +875,14 @@ describe('renderOpcodesInto', () => {
it('should render hello world', () => {
scratch.ensureElements();
- const opcodes = renderToString(
+ renderToString(
Hello World
,
+ scratch,
);
- renderOpcodesInto(opcodes, scratch);
+ // renderOpcodesInto(opcodes, scratch);
expect(scratch.__element_root).toMatchInlineSnapshot(`
{
it('should render attr', () => {
scratch.ensureElements();
- const opcodes = renderToString(
+ renderToString(
Hello World
,
+ scratch,
);
- renderOpcodesInto(opcodes, scratch);
+ // renderOpcodesInto(opcodes, scratch);
expect(scratch.__element_root).toMatchInlineSnapshot(`
{
it('should render string', () => {
scratch.ensureElements();
- const opcodes = renderToString(
+ renderToString(
Hello World
{'aaaa'.toUpperCase()}
,
+ scratch,
);
- renderOpcodesInto(opcodes, scratch);
+ // renderOpcodesInto(opcodes, scratch);
expect(scratch.__element_root).toMatchInlineSnapshot(`
{
it('should render with multi-children', () => {
scratch.ensureElements();
- const opcodes = renderToString(
+ renderToString(
Hello World
{[A, B, C]}
,
+ scratch,
);
- renderOpcodesInto(opcodes, scratch);
+ // renderOpcodesInto(opcodes, scratch);
expect(scratch.__element_root).toMatchInlineSnapshot(`
{
);
- const opcodes = renderToString(
+ renderToString(
Hello World
{[reuse, reuse]}
,
+ scratch,
);
- renderOpcodesInto(opcodes, scratch);
+ // renderOpcodesInto(opcodes, scratch);
expect(scratch.__element_root).toMatchInlineSnapshot(`
{
return ;
}
- const opcodes = renderToString();
- renderOpcodesInto(opcodes, scratch);
+ renderToString(, scratch);
+ // renderOpcodesInto(opcodes, scratch);
expect(scratch.__element_root).toMatchInlineSnapshot(`
{
Counter.defaultProps = { count: 1 };
- const opcodes = renderToString();
- renderOpcodesInto(opcodes, scratch);
+ renderToString(, scratch);
+ // renderOpcodesInto(opcodes, scratch);
expect(scratch.__element_root).toMatchInlineSnapshot(`
{
it('should render empty array', () => {
scratch.ensureElements();
- renderOpcodesInto([], scratch);
+ renderToString([], scratch);
expect(scratch.__element_root).toMatchInlineSnapshot(`
{
return children;
}
- const opcodes = renderToString(
+ renderToString(
Hello World
{[
@@ -891,9 +1153,10 @@ describe('renderOpcodesInto', () => {
D{[D1, D2, D3, D4]},
]}
,
+ scratch,
);
- renderOpcodesInto(opcodes, scratch);
+ // renderOpcodesInto(opcodes, scratch);
scratch.__firstChild.removeChild(scratch.__firstChild.__firstChild);
scratch.__firstChild.removeChild(scratch.__firstChild.__lastChild);
@@ -976,7 +1239,7 @@ describe('createElement', () => {
{
"children": undefined,
"extraProps": undefined,
- "id": -89,
+ "id": -41,
"type": "__snapshot_a94a8_test_74",
"values": undefined,
},
@@ -990,7 +1253,7 @@ describe('createElement', () => {
{
"children": undefined,
"extraProps": undefined,
- "id": -90,
+ "id": -42,
"type": "__snapshot_a94a8_test_74",
"values": undefined,
},
@@ -1012,7 +1275,7 @@ describe('createElement', () => {
{
"children": undefined,
"extraProps": undefined,
- "id": -91,
+ "id": -43,
"type": "__snapshot_a94a8_test_75",
"values": undefined,
},
@@ -1026,7 +1289,7 @@ describe('createElement', () => {
{
"children": undefined,
"extraProps": undefined,
- "id": -92,
+ "id": -44,
"type": "__snapshot_a94a8_test_75",
"values": undefined,
},
diff --git a/packages/react/runtime/__test__/snapshot/workletRef.test.jsx b/packages/react/runtime/__test__/snapshot/workletRef.test.jsx
index c40847d0a2..8fe5e3b0e6 100644
--- a/packages/react/runtime/__test__/snapshot/workletRef.test.jsx
+++ b/packages/react/runtime/__test__/snapshot/workletRef.test.jsx
@@ -591,13 +591,18 @@ describe('WorkletRef', () => {
});
it('invalid ref type', async function() {
+ const reportError = lynx.reportError;
+ lynx.reportError = vi.fn();
// main thread render
{
__root.__jsx = createCompMT1('number');
- expect(() => renderPage()).toThrowError(
- 'MainThreadRef: main-thread:ref must be of type MainThreadRef or main-thread function.',
- );
+ renderPage();
}
+ expect(lynx.reportError).toHaveBeenCalledTimes(1);
+ expect(lynx.reportError).toHaveBeenCalledWith(
+ new Error('MainThreadRef: main-thread:ref must be of type MainThreadRef or main-thread function.'),
+ );
+ lynx.reportError = reportError;
});
});
diff --git a/packages/react/runtime/src/lifecycle/render.ts b/packages/react/runtime/src/lifecycle/render.ts
index 153ea55d1d..1382cf1752 100644
--- a/packages/react/runtime/src/lifecycle/render.ts
+++ b/packages/react/runtime/src/lifecycle/render.ts
@@ -6,10 +6,7 @@
* Implements the IFR (Instant First-Frame Rendering) on main thread.
*/
-import { isValidElement } from 'preact';
-
import { profileEnd, profileStart } from '../debug/profile.js';
-import { renderOpcodesInto } from '../opcodes.js';
import { render as renderToString } from '../renderToOpcodes/index.js';
import { __root } from '../root.js';
import { SnapshotInstance } from '../snapshot/snapshot.js';
@@ -20,31 +17,20 @@ function renderMainThread(): void {
if (typeof __PROFILE__ !== 'undefined' && __PROFILE__) {
profileStart('ReactLynx::renderMainThread');
}
- opcodes = renderToString(__root.__jsx, undefined);
+ opcodes = renderToString(__root.__jsx, undefined, __root as SnapshotInstance);
} catch (e) {
lynx.reportError(e as Error);
opcodes = [];
+ (__root as SnapshotInstance).removeChildren();
} finally {
if (typeof __PROFILE__ !== 'undefined' && __PROFILE__) {
profileEnd();
}
}
- if (process.env['NODE_ENV'] === 'test') {
- opcodes = opcodes.map((opcode) => {
- if (isValidElement(opcode) && typeof opcode.type === 'string') {
- return Object.assign(new SnapshotInstance(opcode.type), opcode, { $$typeof: undefined });
- }
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
- return opcode;
- });
- }
-
if (typeof __PROFILE__ !== 'undefined' && __PROFILE__) {
profileStart('ReactLynx::renderOpcodes');
}
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
- renderOpcodesInto(opcodes, __root as any);
if (__ENABLE_SSR__) {
__root.__opcodes = opcodes;
}
diff --git a/packages/react/runtime/src/opcodes.ts b/packages/react/runtime/src/opcodes.ts
index 352488e1f9..881bc6548a 100644
--- a/packages/react/runtime/src/opcodes.ts
+++ b/packages/react/runtime/src/opcodes.ts
@@ -95,59 +95,59 @@ export function ssrHydrateByOpcodes(
}
}
-export function renderOpcodesInto(opcodes: any[], into: SnapshotInstance): void {
- let top: SnapshotInstance = into;
- const stack: SnapshotInstance[] = [into];
- for (let i = 0; i < opcodes.length;) {
- const opcode = opcodes[i];
- switch (opcode) {
- case OpcodeBegin: {
- const p = top;
- top = opcodes[i + 1];
- // @ts-ignore
- if (top.__parent) {
- // already inserted
- top = new SnapshotInstance(top.type);
- opcodes[i + 1] = top;
- }
- p.insertBefore(top);
- stack.push(top);
+// export function renderOpcodesInto(opcodes: any[], into: SnapshotInstance): void {
+// let top: SnapshotInstance = into;
+// const stack: SnapshotInstance[] = [into];
+// for (let i = 0; i < opcodes.length;) {
+// const opcode = opcodes[i];
+// switch (opcode) {
+// case OpcodeBegin: {
+// const p = top;
+// top = opcodes[i + 1];
+// // @ts-ignore
+// if (top.__parent) {
+// // already inserted
+// top = new SnapshotInstance(top.type);
+// opcodes[i + 1] = top;
+// }
+// p.insertBefore(top);
+// stack.push(top);
- i += 2;
- break;
- }
- case OpcodeEnd: {
- // @ts-ignore
- top[CHILDREN] = undefined;
+// i += 2;
+// break;
+// }
+// case OpcodeEnd: {
+// // @ts-ignore
+// top[CHILDREN] = undefined;
- stack.pop();
- const p = stack[stack.length - 1];
- top = p!;
+// stack.pop();
+// const p = stack[stack.length - 1];
+// top = p!;
- i += 1;
- break;
- }
- case OpcodeAttr: {
- const key = opcodes[i + 1];
- const value = opcodes[i + 2];
- top.setAttribute(key, value);
+// i += 1;
+// break;
+// }
+// case OpcodeAttr: {
+// const key = opcodes[i + 1];
+// const value = opcodes[i + 2];
+// top.setAttribute(key, value);
- i += 3;
- break;
- }
- case OpcodeText: {
- const text = opcodes[i + 1];
- const s = new SnapshotInstance(null as unknown as string);
- if (__ENABLE_SSR__) {
- // We need store the just created SnapshotInstance, or it will be lost when we leave the function
- opcodes[i + 1] = [s, text];
- }
- s.setAttribute(0, text);
- top.insertBefore(s);
+// i += 3;
+// break;
+// }
+// case OpcodeText: {
+// const text = opcodes[i + 1];
+// const s = new SnapshotInstance(null as unknown as string);
+// if (__ENABLE_SSR__) {
+// // We need store the just created SnapshotInstance, or it will be lost when we leave the function
+// opcodes[i + 1] = [s, text];
+// }
+// s.setAttribute(0, text);
+// top.insertBefore(s);
- i += 2;
- break;
- }
- }
- }
-}
+// i += 2;
+// break;
+// }
+// }
+// }
+// }
diff --git a/packages/react/runtime/src/renderToOpcodes/index.ts b/packages/react/runtime/src/renderToOpcodes/index.ts
index 7de5d6589a..475d595fd7 100644
--- a/packages/react/runtime/src/renderToOpcodes/index.ts
+++ b/packages/react/runtime/src/renderToOpcodes/index.ts
@@ -10,7 +10,8 @@
// @ts-nocheck
-import { Fragment, h, options } from 'preact';
+import { Fragment, h, options, isValidElement } from 'preact';
+import { SnapshotInstance } from '../snapshot/snapshot.js';
import {
CHILDREN,
@@ -41,7 +42,7 @@ let beforeDiff, beforeDiff2, afterDiff, renderHook, ummountHook;
* @param {VNode} vnode JSX Element / VNode to render
* @param {object} [context] Initial root context object
*/
-export function renderToString(vnode: any, context: any): any[] {
+export function renderToString(vnode: any, context: any, into: SnapshotInstance): any[] {
// Performance optimization: `renderToString` is synchronous and we
// therefore don't execute any effects. To do that we pass an empty
// array to `options._commit` (`__c`). But we can go one step further
@@ -71,6 +72,7 @@ export function renderToString(vnode: any, context: any): any[] {
parent,
opcodes,
0,
+ into,
);
} finally {
// options._commit, we don't schedule any effects in this library right now,
@@ -144,7 +146,9 @@ function renderClassComponent(vnode, context) {
* @param {boolean} isSvgMode
* @param {any} selectValue
* @param {VNode} parent
- * @param opcodes
+ * @param {any[]} opcodes
+ * @param {number} opcodesLength
+ * @param {SnapshotInstance} into
*/
function _renderToString(
vnode,
@@ -154,6 +158,7 @@ function _renderToString(
parent,
opcodes,
opcodesLength,
+ into,
) {
// Ignore non-rendered VNodes/values
if (vnode == null || vnode === true || vnode === false || vnode === '') {
@@ -163,8 +168,7 @@ function _renderToString(
// Text VNodes: escape as HTML
if (typeof vnode !== 'object') {
if (typeof vnode === 'function') return;
-
- opcodes.push(__OpText, vnode + '');
+ renderToTextNode(into, vnode + '', opcodes);
return;
}
@@ -175,7 +179,18 @@ function _renderToString(
const child = vnode[i];
if (child == null || typeof child === 'boolean') continue;
- _renderToString(child, context, isSvgMode, selectValue, parent, opcodes, opcodes.length);
+ _renderToString(
+ child,
+ context,
+ isSvgMode,
+ selectValue,
+ parent,
+ opcodes,
+ /* v8 ignore start */
+ __ENABLE_SSR__ ? opcodes.length : 0,
+ /* v8 ignore end */
+ into,
+ );
}
return;
}
@@ -251,10 +266,28 @@ function _renderToString(
&& rendered.key == null;
rendered = isTopLevelFragment ? rendered.props.children : rendered;
+ let lastChild = into.__lastChild;
// Recurse into children before invoking the after-diff hook
try {
- _renderToString(rendered, context, isSvgMode, selectValue, vnode, opcodes, opcodes.length);
+ _renderToString(
+ rendered,
+ context,
+ isSvgMode,
+ selectValue,
+ vnode,
+ opcodes,
+ /* v8 ignore start */
+ __ENABLE_SSR__ ? opcodes.length : 0,
+ /* v8 ignore end */
+ into,
+ );
} catch (e) {
+ // clear existing children
+ into.removeChildren(
+ lastChild
+ ? lastChild.__nextSibling
+ : into.__firstChild,
+ );
if (e && typeof e === 'object' && e.then && component && /* _childDidSuspend */ component.__c) {
component.setState({ /* _suspended */ __a: true });
@@ -262,8 +295,21 @@ function _renderToString(
rendered = renderClassComponent(vnode, context);
component = vnode[COMPONENT];
- opcodes.length = opcodesLength;
- _renderToString(rendered, context, isSvgMode, selectValue, vnode, opcodes, opcodes.length);
+ if (__ENABLE_SSR__) {
+ opcodes.length = opcodesLength;
+ }
+ _renderToString(
+ rendered,
+ context,
+ isSvgMode,
+ selectValue,
+ vnode,
+ opcodes,
+ /* v8 ignore start */
+ __ENABLE_SSR__ ? opcodes.length : 0,
+ /* v8 ignore end */
+ into,
+ );
}
} else {
throw e;
@@ -280,7 +326,18 @@ function _renderToString(
let children;
- opcodes.push(__OpBegin, vnode);
+ // hack for runtime test
+ if (process.env['NODE_ENV'] === 'test' && isValidElement(vnode) && typeof vnode.type === 'string') {
+ vnode = Object.assign(new SnapshotInstance(type), vnode, { $$typeof: undefined });
+ }
+ // already inserted
+ if (vnode.__parent) {
+ vnode = new SnapshotInstance(type);
+ }
+ if (__ENABLE_SSR__) {
+ opcodes.push(__OpBegin, vnode);
+ }
+ into.insertBefore(vnode);
for (const name in props) {
const v = props[name];
@@ -303,23 +360,40 @@ function _renderToString(
// write this attribute to the buffer
if (v != null && v !== false && typeof v !== 'function') {
- opcodes.push(__OpAttr, name, v);
+ if (__ENABLE_SSR__) {
+ opcodes.push(__OpAttr, name, v);
+ }
+ vnode.setAttribute(name, v);
}
}
if (typeof children === 'string' || typeof children === 'number') {
// single text child
- opcodes.push(__OpText, children);
+ renderToTextNode(vnode, children, opcodes);
} else if (children != null && children !== false && children !== true) {
// recurse into this element VNode's children
- _renderToString(children, context, false, selectValue, vnode, opcodes, opcodes.length);
+ _renderToString(
+ children,
+ context,
+ false,
+ selectValue,
+ vnode,
+ opcodes,
+ /* v8 ignore start */
+ __ENABLE_SSR__ ? opcodes.length : 0,
+ /* v8 ignore end */
+ vnode,
+ );
}
if (afterDiff) afterDiff(vnode);
vnode[PARENT] = undefined;
if (ummountHook) ummountHook(vnode);
- opcodes.push(__OpEnd);
+ if (__ENABLE_SSR__) {
+ opcodes.push(__OpEnd);
+ }
+ vnode[CHILDREN] = undefined;
return;
}
@@ -329,6 +403,17 @@ function doRender(props, state, context) {
return this.constructor(props, context);
}
+function renderToTextNode(into: SnapshotInstance, text: string | number, opcodes: Opcode[]) {
+ const textNode = new SnapshotInstance(null);
+ textNode.setAttribute(0, text);
+ into.insertBefore(textNode);
+ if (__ENABLE_SSR__) {
+ // We need store the just created SnapshotInstance, or it will be lost when we leave the function
+ text = [textNode, text];
+ opcodes.push(__OpText, text);
+ }
+}
+
export default renderToString;
export const render: typeof renderToString = renderToString;
export const renderToStaticMarkup: typeof renderToString = renderToString;
diff --git a/packages/react/runtime/src/snapshot/snapshot.ts b/packages/react/runtime/src/snapshot/snapshot.ts
index 62ea06d52a..1464690583 100644
--- a/packages/react/runtime/src/snapshot/snapshot.ts
+++ b/packages/react/runtime/src/snapshot/snapshot.ts
@@ -431,6 +431,16 @@ export class SnapshotInstance {
});
}
+ // remove all children from start or this.__firstChild
+ removeChildren(start: SnapshotInstance | null = this.__firstChild): void {
+ let nodeToRemove = start;
+ while (nodeToRemove) {
+ const next = nodeToRemove.__nextSibling;
+ this.removeChild(nodeToRemove);
+ nodeToRemove = next;
+ }
+ }
+
setAttribute(key: string | number, value: any): void {
if (key === 'values') {
const oldValues = this.__values;
diff --git a/packages/react/testing-library/src/__tests__/alog.test.jsx b/packages/react/testing-library/src/__tests__/alog.test.jsx
index 00a34ac41f..2ebadd6119 100644
--- a/packages/react/testing-library/src/__tests__/alog.test.jsx
+++ b/packages/react/testing-library/src/__tests__/alog.test.jsx
@@ -60,15 +60,6 @@ describe('alog', () => {
[
"[ReactLynxDebug] FiberElement API call #3: __SetCSSId([PAGE#0], 0)",
],
- [
- "[MainThread Component Render] name: ClassComponent",
- ],
- [
- "[MainThread Component Render] name: FunctionComponent",
- ],
- [
- "[MainThread Component Render] name: App",
- ],
[
"[ReactLynxDebug] FiberElement API call #4: __CreateView(0) => VIEW#1",
],
@@ -141,6 +132,9 @@ describe('alog', () => {
[
"[ReactLynxDebug] FiberElement API call #27: __AppendElement(WRAPPER#8, VIEW#9)",
],
+ [
+ "[MainThread Component Render] name: ClassComponent",
+ ],
[
"[ReactLynxDebug] FiberElement API call #28: __CreateView(0) => VIEW#11",
],
@@ -154,7 +148,13 @@ describe('alog', () => {
"[ReactLynxDebug] FiberElement API call #31: __AppendElement(WRAPPER#8, VIEW#11)",
],
[
- "[ReactLynxDebug] FiberElement API call #32: __OnLifecycleEvent(["rLynxFirstScreen", {"root":"{\\"id\\":-1,\\"type\\":\\"root\\",\\"children\\":[{\\"id\\":-2,\\"type\\":\\"__snapshot_426db_test_1\\",\\"values\\":[\\"-2:0:\\",\\"-2:1:\\"],\\"children\\":[{\\"id\\":-3,\\"type\\":\\"wrapper\\",\\"children\\":[{\\"id\\":-7,\\"type\\":null,\\"values\\":[0]}]},{\\"id\\":-4,\\"type\\":\\"wrapper\\",\\"children\\":[{\\"id\\":-5,\\"type\\":\\"__snapshot_426db_test_2\\"},{\\"id\\":-6,\\"type\\":\\"__snapshot_426db_test_3\\"}]}]}]}","jsReadyEventIdSwap":{}}])",
+ "[MainThread Component Render] name: FunctionComponent",
+ ],
+ [
+ "[MainThread Component Render] name: App",
+ ],
+ [
+ "[ReactLynxDebug] FiberElement API call #32: __OnLifecycleEvent(["rLynxFirstScreen", {"root":"{\\"id\\":-1,\\"type\\":\\"root\\",\\"children\\":[{\\"id\\":-2,\\"type\\":\\"__snapshot_426db_test_1\\",\\"values\\":[\\"-2:0:\\",\\"-2:1:\\"],\\"children\\":[{\\"id\\":-3,\\"type\\":\\"wrapper\\",\\"children\\":[{\\"id\\":-4,\\"type\\":null,\\"values\\":[0]}]},{\\"id\\":-5,\\"type\\":\\"wrapper\\",\\"children\\":[{\\"id\\":-6,\\"type\\":\\"__snapshot_426db_test_2\\"},{\\"id\\":-7,\\"type\\":\\"__snapshot_426db_test_3\\"}]}]}]}","jsReadyEventIdSwap":{}}])",
],
[
"[ReactLynxDebug] BTS -> MTS updateMainThread:
@@ -193,7 +193,7 @@ describe('alog', () => {
"snapshotPatch": [
{
"op": "SetAttribute",
- "id": -7,
+ "id": -4,
"dynamicPartIndex": 0,
"value": 1
}
@@ -255,7 +255,7 @@ describe('alog', () => {
"type": "wrapper",
"children": [
{
- "id": -7,
+ "id": -4,
"type": null,
"values": [
0
@@ -264,15 +264,15 @@ describe('alog', () => {
]
},
{
- "id": -4,
+ "id": -5,
"type": "wrapper",
"children": [
{
- "id": -5,
+ "id": -6,
"type": "__snapshot_426db_test_2"
},
{
- "id": -6,
+ "id": -7,
"type": "__snapshot_426db_test_3"
}
]
@@ -289,10 +289,10 @@ describe('alog', () => {
| -1(root): undefined
| -2(__snapshot_426db_test_1): ["-2:0:","-2:1:"]
| -3(wrapper): undefined
- | -7(null): [0]
- | -4(wrapper): undefined
- | -5(__snapshot_426db_test_2): undefined
- | -6(__snapshot_426db_test_3): undefined",
+ | -4(null): [0]
+ | -5(wrapper): undefined
+ | -6(__snapshot_426db_test_2): undefined
+ | -7(__snapshot_426db_test_3): undefined",
],
[
"[ReactLynxDebug] BackgroundSnapshotInstance tree before hydration:
@@ -309,10 +309,10 @@ describe('alog', () => {
| -1(root): undefined
| -2(__snapshot_426db_test_1): [null,null]
| -3(wrapper): undefined
- | -7(null): [0]
- | -4(wrapper): undefined
- | -5(__snapshot_426db_test_2): undefined
- | -6(__snapshot_426db_test_3): undefined",
+ | -4(null): [0]
+ | -5(wrapper): undefined
+ | -6(__snapshot_426db_test_2): undefined
+ | -7(__snapshot_426db_test_3): undefined",
],
[
"[ReactLynxDebug] BTS received event:
@@ -333,10 +333,10 @@ describe('alog', () => {
}",
],
[
- "[BackgroundThread Component Render] name: ClassComponent, uniqID: __snapshot_426db_test_2, __id: -5",
+ "[BackgroundThread Component Render] name: ClassComponent, uniqID: __snapshot_426db_test_2, __id: -6",
],
[
- "[BackgroundThread Component Render] name: FunctionComponent, uniqID: __snapshot_426db_test_3, __id: -6",
+ "[BackgroundThread Component Render] name: FunctionComponent, uniqID: __snapshot_426db_test_3, __id: -7",
],
[
"[BackgroundThread Component Render] name: App, uniqID: __snapshot_426db_test_1, __id: -2",
@@ -363,7 +363,7 @@ describe('alog', () => {
"snapshotPatch": [
{
"op": "SetAttribute",
- "id": -7,
+ "id": -4,
"dynamicPartIndex": 0,
"value": 0
}
@@ -394,10 +394,10 @@ describe('alog', () => {
expect(lynxTestingEnv.backgroundThread.console.alog.mock.calls).toMatchInlineSnapshot(`
[
[
- "[BackgroundThread Component Render] name: ClassComponent, uniqID: __snapshot_426db_test_2, __id: -5",
+ "[BackgroundThread Component Render] name: ClassComponent, uniqID: __snapshot_426db_test_2, __id: -6",
],
[
- "[BackgroundThread Component Render] name: FunctionComponent, uniqID: __snapshot_426db_test_3, __id: -6",
+ "[BackgroundThread Component Render] name: FunctionComponent, uniqID: __snapshot_426db_test_3, __id: -7",
],
[
"[BackgroundThread Component Render] name: App, uniqID: __snapshot_426db_test_1, __id: -2",
@@ -424,7 +424,7 @@ describe('alog', () => {
"snapshotPatch": [
{
"op": "SetAttribute",
- "id": -7,
+ "id": -4,
"dynamicPartIndex": 0,
"value": 1
}
@@ -455,10 +455,10 @@ describe('alog', () => {
expect(lynxTestingEnv.backgroundThread.console.alog.mock.calls).toMatchInlineSnapshot(`
[
[
- "[BackgroundThread Component Render] name: ClassComponent, uniqID: __snapshot_426db_test_2, __id: -5",
+ "[BackgroundThread Component Render] name: ClassComponent, uniqID: __snapshot_426db_test_2, __id: -6",
],
[
- "[BackgroundThread Component Render] name: FunctionComponent, uniqID: __snapshot_426db_test_3, __id: -6",
+ "[BackgroundThread Component Render] name: FunctionComponent, uniqID: __snapshot_426db_test_3, __id: -7",
],
[
"[BackgroundThread Component Render] name: App, uniqID: __snapshot_426db_test_1, __id: -2",
diff --git a/packages/react/testing-library/src/__tests__/list.test.jsx b/packages/react/testing-library/src/__tests__/list.test.jsx
index 1bdfef64f8..775a16cab7 100644
--- a/packages/react/testing-library/src/__tests__/list.test.jsx
+++ b/packages/react/testing-library/src/__tests__/list.test.jsx
@@ -890,7 +890,7 @@ describe('list - deferred should render as normal', () => {
"rLynxFirstScreen",
{
"jsReadyEventIdSwap": {},
- "root": "{"id":-1,"type":"root","children":[{"id":-2,"type":"__snapshot_a9e46_test_30","children":[{"id":-3,"type":"__snapshot_a9e46_test_31","values":[{"item-key":0}],"children":[{"id":-4,"type":"__snapshot_a9e46_test_29","values":[{"style":{"backgroundColor":"red","margin":"12px"}}],"children":[{"id":-5,"type":"__snapshot_a9e46_test_32","children":[{"id":-12,"type":null,"values":[0]}]}]}]},{"id":-6,"type":"__snapshot_a9e46_test_31","values":[{"item-key":1}],"children":[{"id":-7,"type":"__snapshot_a9e46_test_29","values":[{"style":{"backgroundColor":"red","margin":"12px"}}],"children":[{"id":-8,"type":"__snapshot_a9e46_test_32","children":[{"id":-13,"type":null,"values":[1]}]}]}]},{"id":-9,"type":"__snapshot_a9e46_test_31","values":[{"item-key":2}],"children":[{"id":-10,"type":"__snapshot_a9e46_test_29","values":[{"style":{"backgroundColor":"red","margin":"12px"}}],"children":[{"id":-11,"type":"__snapshot_a9e46_test_32","children":[{"id":-14,"type":null,"values":[2]}]}]}]}]}]}",
+ "root": "{"id":-1,"type":"root","children":[{"id":-2,"type":"__snapshot_a9e46_test_30","children":[{"id":-3,"type":"__snapshot_a9e46_test_31","values":[{"item-key":0}],"children":[{"id":-4,"type":"__snapshot_a9e46_test_29","values":[{"style":{"backgroundColor":"red","margin":"12px"}}],"children":[{"id":-5,"type":"__snapshot_a9e46_test_32","children":[{"id":-6,"type":null,"values":[0]}]}]}]},{"id":-7,"type":"__snapshot_a9e46_test_31","values":[{"item-key":1}],"children":[{"id":-8,"type":"__snapshot_a9e46_test_29","values":[{"style":{"backgroundColor":"red","margin":"12px"}}],"children":[{"id":-9,"type":"__snapshot_a9e46_test_32","children":[{"id":-10,"type":null,"values":[1]}]}]}]},{"id":-11,"type":"__snapshot_a9e46_test_31","values":[{"item-key":2}],"children":[{"id":-12,"type":"__snapshot_a9e46_test_29","values":[{"style":{"backgroundColor":"red","margin":"12px"}}],"children":[{"id":-13,"type":"__snapshot_a9e46_test_32","children":[{"id":-14,"type":null,"values":[2]}]}]}]}]}]}",
},
],
],