Skip to content

perf(hooks): stabilize Escape and outside-click callbacks - #8562

Open
joshblack wants to merge 3 commits into
mainfrom
joshblack/react-compiler-stable-callbacks
Open

joshblack wants to merge 3 commits into
mainfrom
joshblack/react-compiler-stable-callbacks

Conversation

@joshblack

Copy link
Copy Markdown
Member

Follow up to #8558.

This PR updates useOnEscapePress and useOnOutsideClick to use our existing effect-synchronized callback helper. Callback changes no longer re-register their event handlers or reattach the document listener.

The public APIs stay the same, including explicit callback dependencies passed to useOnEscapePress. This is preparation for its compiler migration; useOnEscapePress remains excluded while we preserve that dependency-array contract.

Changelog

New

Changed

  • Update Escape and outside-click handlers to keep event subscriptions stable when callbacks change.
  • Update Escape handler IDs to use lazy state initialization, matching outside-click handlers.

Removed

Rollout strategy

This is a patch performance improvement with no public API changes.

  • No changes needed in github/github-ui
  • Needs changes in github/github-ui
  • Ships with feature flag(s)
  • Not sure
  • None

@joshblack
joshblack added this pull request to stack #8559 October 16, 2026 15:55
@changeset-bot

changeset-bot Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e7b3ff6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/react Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added staff Author is a staff member integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm labels Oct 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Action required

👋 Hi, this pull request contains changes to the source code that github/github-ui depends on. If you are GitHub staff, test these changes with github/github-ui using the integration workflow. Check the integration testing docs for step-by-step instructions. Or, apply the integration-tests: skipped manually label to skip these checks.

Comment thread packages/react/src/hooks/useOnEscapePress.ts
Comment thread .changeset/stable-event-hook-callbacks.md

@joshblack joshblack left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@copilot I don't think you need to restoreAllMocks afterEach test. Remove this. Also why did you add this? Share the source for this, if any, from skills or instructions.

Base automatically changed from joshblack/react-compiler-hooks to main October 20, 2026 16:45
@joshblack
joshblack force-pushed the joshblack/react-compiler-stable-callbacks branch from 6325dfb to cd43ddd Compare October 20, 2026 16:45
@joshblack
joshblack marked this pull request as ready for review October 20, 2026 16:45
@joshblack
joshblack requested a review from a team as a code owner October 20, 2026 16:45
@joshblack
joshblack requested review from francinelucca and a balanced review from Copilot October 20, 2026 16:45

@joshblack joshblack left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@copilot honestly just use the afterAll, that's fine compared to this approach

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

Static review found no blocking issues, and regression coverage addresses the preserved contracts; tests were not executed.

No open issues 🎉

What changed in this PR

Stabilizes Escape and outside-click subscriptions in Primer React, preparing for further compiler migration without changing public APIs.

Changes:

  • Reuses effect-synchronized callbacks to avoid listener churn.
  • Lazily initializes Escape handler IDs.
  • Adds regression coverage and a patch changeset.
File Description
packages/​react/​src/​hooks/​useOnOutsideClick.tsx Stabilizes outside-click callbacks.
packages/​react/​src/​hooks/​useOnEscapePress.ts Stabilizes callbacks and lazily initializes IDs.
packages/​react/​src/​hooks/​__tests__/​useOnOutsideClick.test.tsx Tests callback updates, listener stability, and cleanup.
packages/​react/​src/​hooks/​__tests__/​useOnEscapePress.test.tsx Tests listener stability, dependencies, cleanup, and nested priority.
.changeset/​stable-event-hook-callbacks.md Records the patch performance improvement.

Review effort: Balanced

@github-actions
github-actions Bot requested a deployment to storybook-preview-8562 October 20, 2026 16:53 Abandoned

Copilot AI commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

@copilot I don't think you need to restoreAllMocks afterEach test. Remove this. Also why did you add this? Share the source for this, if any, from skills or instructions.

Removed both afterEach(() => vi.restoreAllMocks()) blocks in ef5b964. The tests now restore only their own document-listener spies locally.

I added the broad cleanup as a test-isolation precaution for those spies, not because a skill or instruction required it. I found no supporting guidance to cite; the suite-wide cleanup was unnecessary.

All 11 affected tests and the full repository checks passed (2,901 tests, build, type checking, lint, and formatting).

Copilot AI commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

@copilot I don't think you need to restoreAllMocks afterEach test. Remove this. Also why did you add this? Share the source for this, if any, from skills or instructions.

There wasn't a source for the afterEach cleanup in the skills or instructions; I added it defensively to avoid spies leaking between tests. I removed that and switched to suite-level cleanup in afterAll per your follow-up.

@copilot honestly just use the afterAll, that's fine compared to this approach

Switched both hook test files to restore spies in afterAll. Commit: 318b64f.

@github-actions
github-actions Bot temporarily deployed to storybook-preview-8562 October 20, 2026 17:12 Inactive
joshblack and others added 3 commits October 20, 2026 14:07
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e632d4e3-54d2-4423-9888-8e37b00494a3
Co-authored-by: joshblack <3901764+joshblack@users.noreply.github.com>
Co-authored-by: joshblack <3901764+joshblack@users.noreply.github.com>
@primer-integration

primer-integration Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Integration test results from github/github-ui PR:

Waiting  Changes   Waiting
Passed  CI   Passed
Waiting  VRT   Waiting
Running  Projects   Running

@github-actions github-actions Bot added integration-tests: failing Changes in this PR cause breaking changes in gh/gh and removed integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm labels Oct 20, 2026

This branch was successfully deployed

2 active deployments
storybook-preview-8562 — e7b3ff67 Deployed Oct 20, 2026 by github-actions[bot]
github-pages — e7b3ff67 Deployed Oct 20, 2026 by joshblack via deploy-preview #33812
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration-tests: failing Changes in this PR cause breaking changes in gh/gh staff Author is a staff member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants