Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork2.8k
chore(website): preserve RulesTable filters state in searchParams#6568
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
nx-cloudbot commentedMar 4, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Thanks for the PR,@hasparus! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently onhttps://opencollective.com/typescript-eslint. |
netlifybot commentedMar 4, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
✅ Deploy Preview fortypescript-eslint ready!
To edit notification comments on pull requests, go to yourNetlify site settings. |
Yeah 😞.#6508 |
test('Accessibility', async ({ page }) => { | ||
await new AxeBuilder({ page }).analyze(); | ||
}); |
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.
😍 thanks for adding this in!
(I'll continue reviewing soon, just wanted to express appreciation sooner)
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.
Yup, this looks great. Thanks for sending it in@hasparus!
Just one suggestion on refactoringRulesTable
<>useRulesFilters
a bit. What do you think?
I'm down to merge as-is if you don't like the suggestion, or make it myself if you don't have time.
@@ -122,78 +123,57 @@ export default function RulesTable({ | |||
}: { | |||
extensionRules?: boolean; | |||
}): JSX.Element { | |||
const [filters, changeFilter] = useRulesFilters( | |||
extensionRules ? 'extension-rules' : 'supported-rules', | |||
); |
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.
[Cleanup] I'm not a big fan of hardcoding IDs on boolean logic. It tends to break over time, and makes it harder to understand where the IDs come from. How about giving theRulesTable
component a mandatoryid
prop that's then passed directly touseRulesFilters
?
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 agree about hardcoding is no boolean logic, but I feel that
<RulesTable>
might be a bit confusing given that the heading above receivesid
attribute from the markdown pipeline.
How about a propruleset: "supported-rules" | "extension-rules"
that would subsume the boolean flagand be usable as a search param key?
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.
Yeah I like that a lot!
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 added it in642031f, but it seems there are indirect codecov changes that are failing the CI. Do you think it's connected to my change?
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.
We can ignore codecov for these website PRs. We don't have great unit test coverage on it anyway. 🤷
nx-cloudbot commentedMar 14, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
hasparus commentedMar 17, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@JoshuaKGoldberg The deploy has finished in 3 minutes, but the status check's been hanging for 19 hours. Is there a way we can stop it or restart it? This seems like a bug in the Netlify integration. @Skn0tt sorry for pinging you here, but I couldn't find acontact button athttps://app.netlify.com/sites/typescript-eslint/deploys/64131d041e22810009b38f2c. |
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.
The implementation looks mostly good to me, but as some extra reading, you may want to tryuseSyncExternalStore
(interesting read) ^^
const [state, setState] = useState(neutralFiltersState); | ||
useIsomorphicLayoutEffect(() => { | ||
const search = new URLSearchParams(window.location.search); |
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 can replacewindow.location
withuseLocation()
so you get SSR safety for free
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 expecteduseLocation()
to trigger re-renders whenever the location changes, as the docs would suggest:https://reactrouter.com/en/main/hooks/use-location
So usinglocation
fromuseLocation
here wouldn't be the same logic, right?
And I'm in auseLayoutEffect
which does not run on the server, so accessingwindow.location
works.
Could you tell me more what do you mean by "SSR safety for free"?
Notice that I had rewritten this logic toreact-router
specific hooks, what I described in"Alternative solution" in the original post. It turned out to be buggy and harder to reason about than the less elegant, naive solution withsetState
anduseLayoutEffect
, so I reverted that change —786557f.
The implementation looks mostly good to me, but as some extra reading, you may want to try useSyncExternalStore (interesting read) ^^
Nice article! Do you think I should rewrite this PR to useuseHistorySelector
presented in the post?
Josh-CenaMar 18, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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'm okay either way! I don't have strong opinions on this, and TBH my React is getting a bit rusty these days. Just thought you may be interested—since effects don't work well with SSR.
Could you tell me more what do you mean by "SSR safety for free"?
I mean you don't have to useuseIsomorphicLayoutEffect
and read from a client-only API inside.useLocation
is available both server-side and client-side, so it's more robust.
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 mean you don't have to use useIsomorphicLayoutEffect and read from a client-only API inside. useLocation is available both server-side and client-side, so it's more robust.
Well, yes, that's true, but then we shouldn't useuseState
, because a change to the location will already re-render the component. Would you agree?
Would you prefer if I went back to the state from7c2e81a? and write end-to-end tests to ensure it works?
(I'll defer to@Josh-Cena - who is more knowledgeable than me on Docusaurus best practices anyway!) |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Oh sorry I missed this - it's been flaky for a while. We can ignore it.#6508 😞 |
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 looks great, if you fix those linting errors i think we are ready to merge
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.
🚀 excellent, thanks@hasparus!
Thanks for the review and bearing with me, guys 🙏 |
Skn0tt commentedApr 3, 2023
Sorry for getting back so late, I was on PTO the past weeks. Not sure what happened here, but it looks like things are alright now? Let me know if not, and i'll see how I can help :) |
Uh oh!
There was an error while loading.Please reload this page.
PR Checklist
Overview
Howdy! 👋
I added syncing rules table filters state to URL search params, and I wrote two test cases for it.
Solution
There are two tables, so I serialised the state to two search params, one for each table
supported-rules
,extension-rules
.Each value is list of categories concatenated with dashes
-
.If
FilterMode
is"include"
, we include the category as issupported-rules=recommended-fixable
If
FilterMode
is"exclude"
, we prefix it withx
. (We can't use!
in the URL.)supported-rules=xrecommended-strict-xfixable
I grouped the state of filters into one objects so it's easier to stringify.
Non-solutions
I initially just added a
useEffect
to update search params after the state change, anduseIsomorphicLayoutEffect
, but the problem was that the initial state would be written to the URL before it was read. I ended up moving writing to the URL to thechangeFilter
function exported fromuseRuleFilters
hook.We need
useIsomorphicLayoutEffect
to read from the URL instead of just using the state initialiser, because initialising different state in SSG and post-hydration would give us a hydration mismatch.Alternative solution
I noticed Docusaurus uses React Router, so in7c2e81a I removed
setState
and synchronization and move the entire state touseLocation
, what in theory sounded better, because we'd just keep it in one place. Unfortunately, this got me a bug where the state wasn't re-read post hydration (useLocation
doesn't rerender again?) and I needed a layout effect again, so I ended up just reverting this change.Example
Screen.Recording.2023-03-04.at.18.28.04.mov