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

fix: useId instead of random number for tooltip ID #3094

Merged
merged 4 commits into from
Feb 27, 2025

Conversation

mcmcgrath13
Copy link
Contributor

Summary

Related Issues or PRs

Alternate approach to #2562, which does not change the API of the Tooltip component. Use React's useId to generate a unique identifier instead of a random number.

This is the expected way to generate IDs, so plays nicely with server side rendering frameworks and is easy to mock for unit or snapshot tests.

Example of jest config for mocking

// Make sure the auto-generated IDs are stable for snapshot testing
jest.mock("react", () => ({
  ...jest.requireActual("react"),
  useId: () => "r:id",
}));

How To Test

This is a pure bugfix/refactor. It makes no change to API or UI

@mcmcgrath13 mcmcgrath13 marked this pull request as ready for review February 24, 2025 14:09
@mcmcgrath13 mcmcgrath13 requested a review from a team as a code owner February 24, 2025 14:09
@mcmcgrath13
Copy link
Contributor Author

@crwallace the README says you are an active maintainer - would you be able to approve running the workflow for the tests?

@mcmcgrath13
Copy link
Contributor Author

@brandonlenz I see you committed to the repo recently - any chance you could approve running the test workflows?

@brandonlenz brandonlenz merged commit d769610 into trussworks:main Feb 27, 2025
6 checks passed
const tooltipID = useRef(
`tooltip-${Math.floor(Math.random() * 900000) + 100000}`
)
const tooltipID = useRef(`tooltip-${genId()}`)
Copy link
Contributor

@mdmower-csnw mdmower-csnw Feb 28, 2025

Choose a reason for hiding this comment

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

@brandonlenz @mcmcgrath13 - genId looks like it disobeys two rules of hooks: hooks should be top-level or in custom hooks, and hooks should not be called conditionally.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

any ideas on how can we get around the conditional here given the polyfill need? We can just rename the helper useGenId for the custom hook part

Copy link
Contributor Author

Choose a reason for hiding this comment

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

started a follow on PR at #3096

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't see any warnings in the console on the hook rules with this PR as is 🤔

Copy link
Contributor

@mdmower-csnw mdmower-csnw Feb 28, 2025

Choose a reason for hiding this comment

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

@mcmcgrath13 - While this project has plugin eslint-plugin-react-hooks installed, none of its rules are enabled. If you add this to the eslint config, you'll see a linting error in function genId.

diff --git a/.eslintrc b/.eslintrc
index 85f1c95..70d76cf 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -65,6 +65,7 @@
     "plugin:security/recommended-legacy",
     "plugin:storybook/recommended",
     "plugin:vitest/recommended",
+    "plugin:react-hooks/recommended",
     "prettier"
   ],
   "rules": {

image

And if you change the name of the function from genId to useId, you'll see the other hook issue I mentioned.

image

I'm not all that familiar with the issue this PR is solving, but maybe the below is a more accurate polyfill for useId?

const useId = () => {
  const id1 = React.useId?.()
  const [id2] = useState(`${Math.floor(Math.random() * 900000) + 100000}`)
  return id1 ?? id2
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

aha - thanks for the tip!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had a similar approach on the follow on, but I like that yours allows getting rid of the useRef entirely, so I've adopted that on the follow on PR

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.

3 participants