Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SelectPanel2 Optimization: Do not add and remove keydown listener for escape key on every render #4581

Closed
bwittenberg opened this issue May 11, 2024 · 1 comment · Fixed by #4601

Comments

@bwittenberg
Copy link
Contributor

Description

SelectPanel2.SelectPanel will call dialogEl.removeEventListener and dialogEl.addEventListener on every render, because the call to React.useEffect is not passed an array of dependencies at this callsite: https://github.com/primer/react/blob/main/packages/react/src/drafts/SelectPanel2/SelectPanel.tsx#L195

The React docs describe this behavior here: https://react.dev/reference/react/useEffect#parameters

If you omit this argument, your Effect will re-run after every re-render of the component.

I suspect the dependency array was an accidental omission.

Why am I filing this bug/optimization issue?

I was interested in making a contribution to this repository, and I wanted to start with a small, low impact change. Select components are interesting to me, so I began reviewing the component to look for ways to help, and I came across this as a potential optimization. It's a nitpick, and may not have any real impact on user performance, so I understand if the maintainers want to close without addressing.

Steps to reproduce

The following test case will fail for me when I added to https://github.com/primer/react/blob/main/packages/react/src/drafts/SelectPanel2/SelectPanel.test.tsx.

Note: This is a fairly "white box" test and relies on implementation details. I find that these kind of tests are useful to check performance optimizations, but the tradeoff is that the tests are more brittle.

// packages/react/src/drafts/SelectPanel2/SelectPanel.test.tsx
  it('should not call addEventListener on each render', async () => {
    const container = render(<SelectPanel title="title">child</SelectPanel>)
    const dialogEl = container.getByRole('dialog', {hidden: true})
    const addEventListenerSpy = jest.spyOn(dialogEl, 'addEventListener')
    const removeEventListenerSpy = jest.spyOn(dialogEl, 'removeEventListener')

    container.rerender(<SelectPanel title="title">child</SelectPanel>)
    expect(addEventListenerSpy).not.toHaveBeenCalled()
    expect(removeEventListenerSpy).not.toHaveBeenCalled()
  })

Version

v36.17.0

Browser

No response

@bwittenberg bwittenberg added the bug Something isn't working label May 11, 2024
@bwittenberg
Copy link
Contributor Author

bwittenberg commented May 11, 2024

If the maintainers are interested, I fixed this issue locally. When I tried the push the branch, permission was denied.

I'm not sure if you are open to contributions or not, but if you are, I'd be happy to open a PR!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants