Commit aecc90d
fix: resolve infinite update loop when using createRoot (React 18)
When using React 18's `createRoot` instead of `ReactDOM.render`, two
code paths cause "Maximum update depth exceeded" errors:
1. FallbackListener.componentDidMount calls setState synchronously,
creating a tight loop: componentDidMount → setState → re-render →
throw promise → Suspense fallback → componentDidMount → ...
Fix: defer onStart to a microtask with Promise.resolve().then(),
breaking the synchronous cycle. Added unmount guard to prevent
setState after unmount.
2. Keeper uses flushSync to set freeze state, which forces synchronous
rendering inside createRoot and bypasses React 18's automatic
batching, amplifying the infinite loop.
Fix: remove flushSync wrapper — the setTimeout already provides
the necessary delay.
Closes #336, Closes #257
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>1 parent 93028bc commit aecc90d
2 files changed
Lines changed: 15 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
13 | 22 | | |
14 | 23 | | |
15 | 24 | | |
| 25 | + | |
16 | 26 | | |
17 | 27 | | |
18 | 28 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
| 3 | + | |
3 | 4 | | |
4 | 5 | | |
5 | 6 | | |
| |||
103 | 104 | | |
104 | 105 | | |
105 | 106 | | |
106 | | - | |
107 | | - | |
108 | | - | |
109 | | - | |
| 107 | + | |
| 108 | + | |
110 | 109 | | |
111 | 110 | | |
112 | 111 | | |
| |||
0 commit comments