-
Notifications
You must be signed in to change notification settings - Fork 9
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
Add showMoreLimit prop #245
Conversation
src/components/FilterGroup.tsx
Outdated
const limited = filterOptions.length > showMoreLimit; | ||
const [showAll, setShowAll] = useState<boolean>(!limited); | ||
|
||
function toggleShowAll() { |
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.
At first I thought we might want to wrap this in a useCallback
, if only for consistency, but after thinking about it more we can probably omit it.
Out of curiosity, if you use an arrow function instead like onClick={e => setShowAll(!showAll)}
does a react-perf eslint rule complain? I was thinking that it might be better to use an arrow function and an eslint-ignore comment, just to be explicit here.
Since toggleShowAll is just passed into a regular button
and not another component I don't think there's benefits of wrapping this in useCallback
src/components/FilterGroup.tsx
Outdated
@@ -104,7 +100,8 @@ export function FilterGroup({ | |||
/> | |||
); | |||
})} | |||
{limited && <button className='text-blue-500 py-1 text-sm' onClick={toggleShowAll}>{showAll ? 'Show Less' : 'Show More'}</button>} | |||
{/* eslint-disable-next-line react-perf/jsx-no-new-function-as-prop */} | |||
{limited && <button className='text-primary py-1 text-sm' onClick={_e => setShowAll(!showAll)}>{showAll ? 'Show Less' : 'Show More'}</button>} |
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.
Can this be multiple lines? You can also replace the _e
with ()
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 if I formatted it right lol, could you take a look?
…/yext/search-ui-react into dev/standardfacets-showmorelimit merge.
src/components/FilterGroup.tsx
Outdated
@@ -85,7 +91,7 @@ export function FilterGroup({ | |||
{renderTitle()} | |||
<CollapsibleSection className={cssClasses.optionsContainer}> | |||
{searchable && <SearchInput className={cssClasses.searchInput} />} | |||
{filterOptions.map(o => { | |||
{filterOptions.slice(0, showAll ? filterOptions.length : showMoreLimit).map(o => { |
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.
did you test if this works properly when typing in the search input? it seems like the search would only be performed on this slice of filter options instead of searching all of the options and then displaying the first few
typing in the search input should also change whether show more/less is displayed depending on how many options match the input text
src/components/FilterGroup.tsx
Outdated
@@ -94,6 +100,11 @@ export function FilterGroup({ | |||
/> | |||
); | |||
})} | |||
{limited && | |||
/* eslint-disable-next-line react-perf/jsx-no-new-function-as-prop */ | |||
<button className='text-primary py-1 text-sm' onClick={() => setShowAll(!showAll)}> |
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.
Instead of using the eslint disable, can we extract the function and call it in onClick?
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 wanted to specifically use the eslint disable instead of using useCallback.
Extracting it to a function doesn't actually give it a stable reference, you have to use useCallback or pull the function out to the top level.
I'm fine with useCallback as well I just think it hurts performance a little because we don't actually need the memoization since this is going into a default button element and not another component (even then it's very arguable but we've been doing it everywhere so should be consistent for now and refactor everything later if we decide otherwise). But performance is not really a concern here! useCallback
also sgtm
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.
ohhh I see-- I totally missed that comment earlier, that's fine we can totally leave it haha
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.
I think I have a slight preference for not using useCallback
here. just because it's not really needed and I'm in favor of not wrapping in useMemo
/useCallback
unless it adds some value
src/components/FilterGroup.tsx
Outdated
@@ -69,6 +72,9 @@ export function FilterGroup({ | |||
}; | |||
}, [customCssClasses]); | |||
|
|||
const limited = filterOptions.length > showMoreLimit; |
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.
Super subjective, but since this is a boolean it might be a tad more legible for the future if it were called isLimited
-- but it's tiny haha
src/components/FilterGroup.tsx
Outdated
@@ -94,6 +100,11 @@ export function FilterGroup({ | |||
/> | |||
); | |||
})} | |||
{limited && | |||
/* eslint-disable-next-line react-perf/jsx-no-new-function-as-prop */ |
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 it's a little nicer if we indent everything after the && in this conditional (lines 104-107) and move the last brace to the next line
I'll be removing the |
{children} | ||
</CollapsibleSection> | ||
</FilterGroupProvider> | ||
); | ||
} | ||
|
||
function CheckboxOptions({ | ||
filterOptions, |
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 these parameters have type any
if you don't specify a type?
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.
Should I make an interface for it?
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
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 could also specify it inline
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.
like { myParam }: { myParam: string }
src/components/FilterGroup.tsx
Outdated
|
||
return ( | ||
<> | ||
{filterOptions.filter(o => { |
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 this can just be filterOptions.filter(shouldRenderOption)
src/components/FilterGroup.tsx
Outdated
}) { | ||
const searchUtilities = useSearchUtilities(); | ||
const { searchValue } = useFilterGroupContext(); | ||
const shouldRenderOption = useCallback((option: { displayName: string, value: unknown }) => { |
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.
does this need a useCallback? We're not passing this function anywhere
{children} | ||
</CollapsibleSection> | ||
</FilterGroupProvider> | ||
); | ||
} | ||
|
||
function CheckboxOptions({ |
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.
Would it make sense to put this component in a separate file?
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.
Tom said since it's an internal component we can just keep it in the same file
src/components/FilterGroup.tsx
Outdated
@@ -119,7 +120,12 @@ function CheckboxOptions({ | |||
}) { | |||
const searchUtilities = useSearchUtilities(); | |||
const { searchValue } = useFilterGroupContext(); | |||
const shouldRenderOption = useCallback((option: { displayName: string, value: unknown }) => { | |||
const shouldRenderOption = (option: | |||
{ displayName?: unknown, value: string | number | boolean | NumberRangeValue }) => { |
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.
Instead of unknown
, could we do string | undefined
here? I can't remember off the top of my head, but we may also be able to do displayName?: string
. The string | undefined
may be redundant because of the optional nature of `displayName.
src/components/FilterGroup.tsx
Outdated
@@ -119,7 +120,12 @@ function CheckboxOptions({ | |||
}) { | |||
const searchUtilities = useSearchUtilities(); | |||
const { searchValue } = useFilterGroupContext(); | |||
const shouldRenderOption = useCallback((option: { displayName: string, value: unknown }) => { | |||
const shouldRenderOption = (option: |
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.
@oshi97 do we not want to wrap this in a useMemo
or a useCallback
? I'm wondering if, as is, we could erroneously re-render if searchValue
and searchUtilities
remained the same.
src/components/FilterGroup.tsx
Outdated
{isLimited && | ||
/* eslint-disable-next-line react-perf/jsx-no-new-function-as-prop */ | ||
<button className='text-primary py-1 text-sm' onClick={() => setShowAll(!showAll)}> | ||
{showAll ? 'Show Less' : 'Show 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.
would this scenario be handled correctly?
filterOptions
>showMoreLimit
, so the options are searchable and have a Show More button displayed- user types in the input which narrows down the matching options to fewer than
showMoreLimit
- there probably shouldn't be a Show More/Less button displayed anymore
Follow-up to (#245) - jest tests didn't catch the bug :(
Add a `showMoreLimit` prop to `StandardFacet`. When the number of options exceeds this limit, display only that many options, a searchable facets input, and a show more button. The show more button, when clicked displays all the options. If the number of options is less than the limit, show all the options and no search bar J=SLAP-2252 TEST=auto Added two new stories: one to show the prop at work, and the second to show what happens when the show more button is pressed
Follow-up to (#245) - jest tests didn't catch the bug :(
Add a
showMoreLimit
prop toStandardFacet
. When the number of options exceeds this limit, display only that many options, a searchable facets input, and a show more button. The show more button, when clicked displays all the options. If the number of options is less than the limit, show all the options and no search barJ=SLAP-2252
TEST=auto
Added two new stories: one to show the prop at work, and the second to show what happens when the show more button is pressed
Note: Coveralls decreased by 0.3% because it doesn't count stories as test coverage