Skip to content

feat: Use onPostCommit to ensure that render/rerender and takeNext promises resolve after effects are run - #18

Merged
phryneas merged 6 commits into
mainfrom
pr/onPostCommit
Oct 27, 2026
Merged

phryneas merged 6 commits into
mainfrom
pr/onPostCommit

Conversation

@phryneas

@phryneas phryneas commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

As reported in #17, since React 19.1, passive effects (useEffect, and the subscription in useSyncExternalStore) can run in a later task than their commit.

That means that with the current approach, render/rerender or even takeNext could trigger before all effects for that render had finished processing.

This switches over to onPostCommit, an api that is not part of the official React types, but has been around stable since React 18, based on this React RFC and implemented in react/react#17910.

React 16.8+ and 17 retain existing behaviour.

@pkg-pr-new

pkg-pr-new Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
undefined https://pkg.pr.new/testing-library/react-render-stream-testing-library/@testing-library/react-render-stream@18

commit: 3d8bb39

@phryneas phryneas changed the title Use onPostCommit to ensure that render/rerender and takeNext promises resolve after effects are run feat: Use onPostCommit to ensure that render/rerender and takeNext promises resolve after effects are run Oct 27, 2026
@phryneas
phryneas requested a balanced review from Copilot October 27, 2026 12:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Stale timeouts from the new effect waits can detach later render consumers and cause false timeouts.

1 open issue
What changed in this PR

This PR updates render-stream synchronization to wait for passive effects, addressing effect timing changes in React 19.1 while retaining a legacy fallback for React 16/17.

Changes:

  • Use Profiler onPostCommit to release render and snapshot consumers after effects run.
  • Add regression tests for subscriptions, overlapping rerenders, skipped commits, and snapshot errors.
  • Update API documentation, legacy React DOM typing, and the Symbol.dispose polyfill.
File Description
tests/​polyfill.js Preserve an existing native Symbol.dispose.
src/​renderWithoutAct.tsx Type legacy React DOM APIs locally for newer type definitions.
src/​renderStream/​createRenderStream.tsx Track effect completion and delay render consumers accordingly.
src/​renderStream/​__tests__/​passiveEffects.test.tsx Test effect ordering and render-stream behavior.
src/​renderHookToSnapshotStream.tsx Document passive-effect completion guarantees.

Review effort: Balanced

Comment thread src/renderStream/createRenderStream.tsx Outdated
@phryneas
phryneas added this pull request to stack #20 October 27, 2026 12:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Skipped renders can time out, legacy timestamp collisions can break commit tracking, and CI lacks coverage for the affected React versions.

1 open issue
2 previously missed issues

In code that hasn't changed since last review

Medium severity Add CI coverage for React 19.1+ and legacy React versions

src/​renderStream/​__tests__/​passiveEffects.test.tsx:10

The new regressions run only against React 19.0.0: package.json pins both React packages to that version, and .github/workflows/ci.yml has no version matrix. This leaves the React 19.1+ delayed-passive-effect behavior motivating this change, and the new React 16/17 fallback, untested in CI. Please add coverage on at least one React 19.1+ version and a legacy version so regressions in these scheduling paths cannot pass validation unnoticed.

Medium severity Use unique tokens for legacy commits sharing the same timestamp

src/​renderStream/​createRenderStream.tsx:254

With a coarse or mocked clock, multiple React 16/17 commits from the same root can share a commitTime and overwrite their pending entries. For interleaved commits A1, B1, A2 from two roots with the same timestamp, A1's timer advances effectsFlushedCount to 3, then B1's timer reads past the recorded renders and throws when accessing phase. Give each legacy fallback a unique per-record token so pending commits cannot overwrite one another.

1 resolved since last review

Review effort: Balanced

Comment thread src/renderStream/createRenderStream.tsx Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Node 20 compatibility and cross-root commit synchronization remain broken, and regression coverage does not include an affected React version.

3 open issues
1 resolved since last review

Review effort: Balanced

Comment thread src/renderStream/createRenderStream.tsx
Comment thread src/renderStream/createRenderStream.tsx
Comment thread src/renderStream/createRenderStream.tsx

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Cross-version effect ordering relies on an untyped React lifecycle hook and legacy timer scheduling that warrant human runtime validation.

No open issues 🎉

3 resolved since last review

Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The commit-tracking rewrite relies on an untyped React lifecycle callback and needs human confirmation of compatibility matrix results.

No open issues 🎉

Review effort: Balanced

@phryneas
phryneas marked this pull request as ready for review October 27, 2026 15:06
@phryneas

Copy link
Copy Markdown
Member Author

Running the build from this over in apollographql/apollo-client#13511 to see if there are any obvious regressions.

@phryneas

Copy link
Copy Markdown
Member Author

All green over there, merging this.

@phryneas
phryneas merged commit a530401 into main Oct 27, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants