-
Notifications
You must be signed in to change notification settings - Fork 6
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: SSR compatibility for textfield #195
Conversation
|
packages/textfield/src/component.tsx
Outdated
|
||
// useId returns a string that includes colons (:), e.g., :r0:, :r1:, etc. | ||
// This string is NOT supported in CSS selectors. Hence the replace. | ||
const id = providedId ?? useId().replace(/:/g, ''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why the original useId
util had to rely on useLayoutEffect
, but would it make sense to move the React useId()
hook to src/useId.ts
and simplify the previous useId
util? I'm mostly thinking about reusing generateId
as prefix, which would ensure unique ids in the case where we have multiple React apps using multiple TextField components on one page. I found an article about that here: https://hetdesai03.medium.com/a-complete-guide-to-useid-hook-in-react-18-22119ecfd87f Wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that old useId
solution exists from react 16 days. This hook was added in React 18.
Notice also our useId
hook used useLayoutEffect
which is a performance pitfall, but it was common to use during React 16 days.
I'd say, we should replace instances of our useId
with React's useId
but maybe not in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TL;DR: Delete src/useId.ts
and import it from react
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. But what about generateId
prefix util that would increase uniqueness of the id? If React's useId
only generates r0
, r1
strings, the chance of multiple TextFields across multiple React apps having the same id is higher. That's why I was thinking that we could maybe prefix those ids with whatever generateId
returns, the same way it was done in the utils.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, the docs says that react will always generate unique id's for each useId within the vdom. Do you think there might be a situation where this won't hold?
multiple TextFields across multiple React apps
Do you mean in case of podlets?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean in case of podlets?
Yes, I was thinking about that :) If there were multiple React apps on a layout/page, served as podlets, then we could theoretically have multiple text fields with the same id, e.g. r0
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so I have updated our useId hook and tested it with other components :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, we have now confirmed that on SSR TextFields, the id is something like "R0ckd"
, "R0chj"
, so 3 additional characters compared to ids generated client-side ("r0", "r1"
). I think we can assume at this point that there's little risk of having multiple client-side-rendered React apps with multiple TextFields, which would resolve in multiple r0
, r1
ids. As mentioned in another comment, I agree that the preferred way to deal with it might be to ask the devs to pass { identifierPrefix: 'react-some-unique-prefix' }
option to the createRoot()
call.
Hey, thanks for fixing this problem so quickly! You're right about multiple React apps on the same page getting the same IDs, unless each app is assigned an unique prefix. The React doc mentions a build-in solution for this, which is kind of obscure and indirect:
Your solution would be much better if it automatically assigns an unique prefix, and just works. Perhaps I'm misunderstanding something, but it looks like the |
@@ -1,13 +1,21 @@ | |||
import React from 'react'; | |||
import { action } from '@storybook/addon-actions'; | |||
import { TextField as TroikaTextField } from '../src'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Troika :aaaaaaaaaaaaaa:
Good point, I tested in a remix app and it was actually breaking hydration. Although, the id's generated on a SSR app was different than just the client side app. Keeping the old logic by updating |
@@ -28,9 +28,8 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>( | |||
} = props; | |||
|
|||
activateI18n(enMessages, nbMessages, fiMessages); | |||
|
|||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💪
## [1.3.1-next.1](v1.3.0...v1.3.1-next.1) (2024-01-24) ### Bug Fixes * SSR compatibility for textfield ([#195](#195)) ([7779237](7779237))
## [1.3.1](v1.3.0...v1.3.1) (2024-01-25) ### Bug Fixes * SSR compatibility for textfield ([#195](#195)) ([7779237](7779237))
Before this change, the value of
id
from the useId hook would initialize with null on server and get a value on client which broke SSR hydration. See screenshot of before:To fix this, we can use the
useId
hook from react which generates this value on server as well, hence no mismatch between server and client. See screenshot below:Notice how the value was printed twice before and only once after. This was because the our homemade useId hook ran only clientside with the useEffect hook.