Skip to content

refactor: revamp pagination UI view logic #10567

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

Merged
merged 17 commits into from
Nov 9, 2023
Merged

Conversation

Parkreiner
Copy link
Member

@Parkreiner Parkreiner commented Nov 7, 2023

Connected to #10452 and #10549

Part 1 (of 2?) for the changes I'm hoping to make for our pagination logic. All the updates here deal with view rendering.

Changes made

  • Refactored a lot of our main PaginationWidgetBase component and its utils file
    • Renamed the external props to make them more clear
    • Split up our pagination button component into NumberedPageButton and PlaceholderPageButton (there were just too many concerns for one component to address without getting messy/tangled)
    • Cleaned up the logic and math for our main pagination algorithm
    • Updated a number of the pagination utilities to handle edge cases better
    • Updated the component's next/previous buttons to have good a11y and give you better feedback if you accidentally try to click them while disabled
  • Did a lot of testing
    • Revamped the existing pagination algo test to describe what each test case was looking to check, and added extra test cases
    • Added an extra test file to check the whether the pagination component is disabled properly (safeguards to make sure we don't get these tickets again)
  • Cleaned up comment formatting and wording for clarity

@Parkreiner Parkreiner requested a review from a team November 7, 2023 23:47
@Parkreiner Parkreiner self-assigned this Nov 7, 2023
@Parkreiner Parkreiner requested review from aslilac and removed request for a team November 7, 2023 23:47
const beforeLastPage = numPages - 1;
const startPage = leftBound > 2 ? leftBound : 2;
const endPage = rightBound < beforeLastPage ? rightBound : beforeLastPage;
if (numPages <= TOTAL_PAGE_BLOCKS) {
Copy link
Member Author

Choose a reason for hiding this comment

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

The diff looks bigger than it is because I moved the "easy" case to the top to reduce some of the function's nesting. Might be worth looking at this with diffs turned off?

Copy link
Member

Choose a reason for hiding this comment

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

love me a good early return, v nice

Copy link
Member

@aslilac aslilac left a comment

Choose a reason for hiding this comment

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

couple small thoughts, but overall looks nice!

Comment on lines +29 to +31
if (!disabled && showDisabledMessage) {
setShowDisabledMessage(false);
}
Copy link
Member

Choose a reason for hiding this comment

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

I still don't like it 💀

Copy link
Member Author

@Parkreiner Parkreiner Nov 8, 2023

Choose a reason for hiding this comment

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

Yeah, I remember seeing an article about it called something like "the ugliest pattern in React" or something.

It is better than using useEffect from a performance standpoint, and I guess also "philosophy" reasons (the React team is getting more bullish about how useEffect should be used strictly to sync with external systems, and if the state already exists inside React, you should do things like this)

Copy link
Member

Choose a reason for hiding this comment

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

and yet we also have the wonderful useSyncExternalStore hook :lolsob:

Copy link
Member Author

Choose a reason for hiding this comment

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

I mean, I get that the hook was mainly designed to help state management tools hook into React, but yeah. React's gonna React

disabled: boolean;
disabledMessage: ReactNode;
onClick: () => void;
"aria-label": string;
Copy link
Member

Choose a reason for hiding this comment

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

Rather than special case this one prop, we should probably just extend HTMLAttributes

Copy link
Member Author

Choose a reason for hiding this comment

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

I can extend it, but the thing is that even if I extend HTMLAttributes or componentPropsWithoutRef, I'll still need to treat aria-label as a special case to enforce that it's required

Copy link
Member

Choose a reason for hiding this comment

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

eh, fair enough.

onClick,
disabled,
disabledMessage,
"aria-label": ariaLabel,
Copy link
Member

Choose a reason for hiding this comment

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

...and instead of destructuring, just catch extra props with ...attrs...

Comment on lines 59 to 60
aria-label={ariaLabel}
aria-disabled={disabled}
Copy link
Member

Choose a reason for hiding this comment

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

...and then spread props onto the target with {...attrs}

if (!isFirstPage) {
onChange(page - 1);
if (!onFirstPage) {
onPageChange(currentPage - 1);
Copy link
Member

Choose a reason for hiding this comment

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

could we rename this to onChangePage? just feels a lot more natural to me

Copy link
Member Author

@Parkreiner Parkreiner Nov 8, 2023

Choose a reason for hiding this comment

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

Yeah, I generally go with the onNoun naming convention. You can have a page change, but you can't have a change page, if that makes sense?

Copy link
Member

Choose a reason for hiding this comment

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

I usually think of it as onAction 🤔 "a change" is kind of a weird "noun". I won't block on it, just my 2¢

Copy link
Member Author

Choose a reason for hiding this comment

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

Just double-checked MDN, and all the more specialized change-based follow the onXChange convention
https://developer.mozilla.org/en-US/docs/Web/Events

I am open to changing prop names for clarity, but my thinking is that it's best to mirror the base HTML standards as closely as possible (same reason why I agree with extending the base HTMLAttributes when possible)

@@ -1,67 +1,74 @@
/**
* Generates a ranged array with an option to step over values.
* Shamelessly stolen from:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#sequence_generator_range
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#sequence_generator_range}
Copy link
Member

Choose a reason for hiding this comment

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

mr. fancy-js-doc-knower :^)

const beforeLastPage = numPages - 1;
const startPage = leftBound > 2 ? leftBound : 2;
const endPage = rightBound < beforeLastPage ? rightBound : beforeLastPage;
if (numPages <= TOTAL_PAGE_BLOCKS) {
Copy link
Member

Choose a reason for hiding this comment

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

love me a good early return, v nice

@Parkreiner Parkreiner merged commit ad3abe3 into main Nov 9, 2023
@Parkreiner Parkreiner deleted the mes/pagination-overhaul branch November 9, 2023 14:10
@github-actions github-actions bot locked and limited conversation to collaborators Nov 9, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants