docs(react-islands): drop the write-during-render guard

Implemented and removed. A render-phase flag cleared on a microtask is
still set when React runs effects, so islands writing from an effect —
the documented correct pattern — would throw. The flag also cannot be
set for an island's own re-renders, so real violations pass silently.

Detecting React's render phase reliably needs React internals, which is
not acceptable in a shipped framework. React already reports the real
hazard, and the getSnapshot caching requirement covers the loop case.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-18 15:33:48 +05:30
co-authored by Claude Opus 5
parent 01a3b3b4e9
commit 5f66c8129c
@@ -127,9 +127,9 @@ record that subscribers and devtools depend on.
Write → action → store notifies → snapshot changes → island re-renders. This terminates cleanly Write → action → store notifies → snapshot changes → island re-renders. This terminates cleanly
**provided writes never occur during render**. Writes belong in event handlers or effects. **provided writes never occur during render**. Writes belong in event handlers or effects.
This rule is enforced in dev (see Error handling), not merely documented. It is also the reason This rule is documented rather than machine-enforced — see "Dropped: the write-during-render
this shape was chosen over generated `bind:` sugar: the cycle stays visible in the author's own guard" below. It is also the reason this shape was chosen over generated `bind:` sugar: the
code rather than being hidden in generated glue. cycle stays visible in the author's own code rather than being hidden in generated glue.
## Compiler and bundler changes ## Compiler and bundler changes
@@ -189,12 +189,38 @@ point.
| Island bundle fails to load | Placeholder remains, warning logged; page stays functional because everything else was server-rendered | | Island bundle fails to load | Placeholder remains, warning logged; page stays functional because everything else was server-rendered |
| Non-serializable props | Compile-time `WRN-ISLAND-PROPS` | | Non-serializable props | Compile-time `WRN-ISLAND-PROPS` |
| Unknown store name | Dev: throw, listing available store names. Prod: warn, return undefined | | Unknown store name | Dev: throw, listing available store names. Prod: warn, return undefined |
| Action fired during render | Dev: throw with a targeted message pointing at the handler/effect rule (React's own warning is too generic to diagnose quickly) | | Action fired during render | Left to React. See "Dropped: the write-during-render guard" below. |
| Cleanup throws on unmount | Caught and logged; navigation must not break | | Cleanup throws on unmount | Caught and logged; navigation must not break |
Islands failing **locally** is the most valuable property of this model: a crashed chart leaves Islands failing **locally** is the most valuable property of this model: a crashed chart leaves
the rest of the page working. the rest of the page working.
## Dropped: the write-during-render guard
The design originally called for a dev-only guard that threw when an island
called a store action during render. It was implemented, then removed: the
mechanism is unreliable in both directions.
- **False positives.** React runs effects before a queued microtask drains, so a
render-phase flag cleared on a microtask is still set inside `useEffect`. An
island writing from an effect — the documented correct pattern — would throw.
- **False negatives.** The flag can only be set from the error boundary`s
render. When an island updates its own state, only the island re-renders, so
the flag is never set and a genuine write-during-render passes silently.
There is no reliable public API for detecting React`s render phase; doing it
properly requires React internals, which is not acceptable in a shipped
framework.
React already covers the real hazard: writing during render that notifies
subscribers produces "Cannot update a component while rendering a different
component", and the infinite-loop case is caught by the `getSnapshot` caching
requirement handled in the store bridge. The custom guard added false positives
without covering anything React misses.
The author-facing rule still stands and is still documented — it is simply not
machine-enforced.
## Testing ## Testing
### Compiler unit tests ### Compiler unit tests