Skip to content

Commit 410db8b

Browse files
authored
fix: getPos race condition in React StrictMode (#2311)
1 parent 72712d3 commit 410db8b

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { BlockNoteEditor, BlockNoteSchema } from "@blocknote/core";
2+
import { BlockNoteView } from "@blocknote/mantine";
3+
import "@blocknote/mantine/style.css";
4+
import { createReactBlockSpec } from "@blocknote/react";
5+
import { StrictMode } from "react";
6+
import { flushSync } from "react-dom";
7+
import { createRoot } from "react-dom/client";
8+
import { afterEach, beforeEach, describe, it } from "vitest";
9+
10+
describe("BlockNoteView Rapid Remount", () => {
11+
let div: HTMLDivElement;
12+
13+
beforeEach(() => {
14+
div = document.createElement("div");
15+
document.body.appendChild(div);
16+
});
17+
18+
afterEach(() => {
19+
document.body.removeChild(div);
20+
});
21+
22+
it("should not crash when remounting BlockNoteView with custom blocks rapidly", async () => {
23+
// Define a custom block that might be sensitive to lifecycle
24+
const Alert = createReactBlockSpec(
25+
{
26+
type: "alert",
27+
propSchema: {
28+
type: {
29+
default: "warning",
30+
},
31+
},
32+
content: "inline",
33+
},
34+
{
35+
render: (props) => {
36+
return (
37+
<div className={"alert"}>
38+
<div className={"inline-content"} ref={props.contentRef} />
39+
</div>
40+
);
41+
},
42+
},
43+
);
44+
45+
const schema = BlockNoteSchema.create().extend({
46+
blockSpecs: {
47+
alert: Alert(),
48+
},
49+
});
50+
51+
const editor = BlockNoteEditor.create({
52+
schema,
53+
initialContent: [
54+
{
55+
type: "paragraph",
56+
content: "Text before",
57+
},
58+
{
59+
type: "alert",
60+
content: "Hello World 1",
61+
},
62+
{
63+
type: "alert",
64+
content: "Hello World 2",
65+
},
66+
{
67+
type: "paragraph",
68+
content: "Text after",
69+
},
70+
],
71+
});
72+
73+
const root = createRoot(div);
74+
75+
// Simulate rapid key changes (remounts)
76+
for (let i = 0; i < 20; i++) {
77+
flushSync(() => {
78+
root.render(
79+
<StrictMode>
80+
<BlockNoteView editor={editor} key={i} />
81+
</StrictMode>,
82+
);
83+
});
84+
// yield to event loop to allow effects to run, triggering the race condition
85+
await new Promise((r) => setTimeout(r, 0));
86+
}
87+
root.unmount();
88+
});
89+
});

0 commit comments

Comments
 (0)