-
Notifications
You must be signed in to change notification settings - Fork 328
Fix vue router regression #13040
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 vue router regression #13040
Conversation
🧪 Storybook is successfully deployed!📊 Dashboard:
|
The integration tests discovered a regression with pre-populate email fields in forms. Added a fix, and re-requested review to just make sure you're ok with it. |
@@ -89,6 +89,10 @@ export default function Registration() { | |||
}, | |||
}) | |||
|
|||
useEffect(() => { |
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.
This is clearly a bad thing
When you add use 'useEffect' to set initial values - you better ask yourself, where the root cause, and solve it first.
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.
defaultValues are cached. To reset them, use the reset API.
with the fact that query search is deferred now, so we initialize it with old value
So I assumed this fix is just "a way of doing" in react forms. Additionally, it has an effect that query navigation inside page will also update the email field (not sure if desirable, but I think it is neat).
Do you prefer making navigating to login page non-transitional? Or have another solution in mind?
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.
Initial value is supposed to be present by the moment of initial rendering. Otherwise you'll keep facing issues like this one. Also, React transitions should be preserved as well, as you claimed in the vue router 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.
Changed the fix. Now no useEffects are needed.
Also, React transitions should be preserved as well, as you claimed in the vue router PR.
This is not what I've written, BTW. I said that these use cases for react transitions may be implemented differenttly
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.
Second point is not an option for us
// would be keeping the "intermediate" state by ourselves and leave window.location.search | ||
// management to router. | ||
if (options.replace ?? false) { | ||
window.history.replaceState(null, '', `?${nextSearchParams.toString()}`) |
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.
This can't be a solution.
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.
What exactly cannot be a solution?
If "using window.location.search" to keep state of current query, then it is how it worked before:
const params = new URLSearchParams(window.location.search) |
I may implement better solution, not relying on window.location.search (as in TODO), but wanted to merge a quick fix first.
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.
Could you add a reference to a code where we update window.location directly?
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.
Could you add a reference to a code where we update window.location directly?
There is no such code. Please, re-read my message carefully: I said keeping state of current query. Previous code was relying on navigate
setting window.location.search
synchronously. This is not something guaranteed, according to my research (but I might be wrong).
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.
In react-router it's always synchronous, same true for window.replaceState(...)
. In the code you mentioned it serves a different purpose - in some edge cases we can have an outdated value in react (because react update states in batch), see: https://react.dev/reference/react/useState#updating-state-based-on-the-previous-state
react-router doesn't provide an option to get the current pending value so we need to read the location directly.
My initial comment was about the workaround with window.history.replaceState
and it's obviously not a solution and I won't let it merged that way.
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.
In react-router it's always synchronous
I wasn't sure, when reading documentation. navigate
may return Promise<void>
: https://reactrouter.com/api/hooks/useNavigate#signature
in some edge cases we can have an outdated value in react (because react update states in batch),
Yes, I know. This is exactly what I meant by "we want window.location.href to be updated immediately, so any subsequent query changes won't override this one."
My initial comment was about the workaround with window.history.replaceState and it's obviously not a solution and I won't let it merged that way.
For me is no so obvious. Why reading window.location.search is ok, but writing window.location.search is not ok?
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.
- It's indirect.
- It happens outside of the router context
- It runs states out-of-sync
- It's not ideomatic.
- This is clearly a hack
- I spent the last year getting rid of code like this.
Reading is fine because we use it only as a pending state.
@@ -40,7 +40,8 @@ export function useSearchParamsState<T = unknown>( | |||
defaultValue: T | (() => T), | |||
predicate: (unknown: unknown) => unknown is T = (unknown): unknown is T => true, | |||
): SearchParamsStateReturnType<T> { | |||
const { router, searchParams } = useRouterInReact() | |||
const { router, searchParams: searchParamsRaw } = useRouterInReact() | |||
const searchParams = React.useDeferredValue(searchParamsRaw) |
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.
Why did you add 'useDefferedValue' here? It exists for a different purpose
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.
Different purpose than what?
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.
You clearly don't need it here because the only purpose for this hook is deferring rendering for the parts of the UI. Why do you want to defer here?
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.
When changing category or current id (the state being kept in search params) we want to defer updating asset table. I thought that it should be the default for every query update. But perhaps you're right, I should use it near actual suspense queries.
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.
In that case we should wrap category change in 'startTransition' (I'm sure we do this already)
Deferred state has completely different purpose compared to 'startTransition'
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.
Deferred state has completely different purpose compared to 'startTransition'
Didn't know that. I was just reading in startTransition
docs, that:
You can wrap an update into a Transition only if you have access to the set function of that state. If you want to start a Transition in response to some prop or a custom Hook return value, try useDeferredValue instead.
ATM the category is based on the context change coming from vue.
…/vue-router-regression
✨ GUI Checks ResultsSummary
See individual check results for more details. ℹ️ Chromatic Tests SkippedChromatic visual regression tests were skipped for this PR. To run the tests and deploy Storybook, add the Note: We skip tests by default to optimize CI costs. Only run them when your UI changes are ready for review. 👮 Lint GUI ResultsCheck Results
🎭 Playwright Test ResultsSummary
|
Pull Request Description
A workaround for #13039
The problems were caused by two factors:
See PR comments to see what should be improved to close the task.
Important Notes
Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
- [ ] Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.Scala,
Java,
TypeScript,
and
Rust
style guides. In case you are using a language not listed above, follow the Rust style guide.
- [ ] Unit tests have been written where possible.- [ ] If meaningful changes were made to logic or tests affecting Enso Cloud integration in the libraries,or the Snowflake database integration, a run of the Extra Tests has been scheduled.