I’ve posted here several times previously about an issue I’ve been facing in my codebase. I am building a dropdown box of Filters
. A Filter
can be a FilterField
, a DatePicker
, etc. These components can be used independently or as part of a SearchBox.
If used inside a SearchBox
, they will share a common handleParamChange
. SearchBox
allows us to group together functionality from multiple filters, including debouncing and input validation. The SearchBox
was previously a HOC but I am refactoring it into a hook. SearchBox
must accomplish three things:
- Pass a common
handleParamChange (param): void
function to all childFilters
. - Generate
Chip
Material UI icons for each activeFilter
. TheChips
also take aonDelete()
prop that corresponds to the filter that generated it. - Avoid imposing any styling or structure on either the
Filters
orChips
. Previously, this was accomplished through a render prop. With theuseSearchBox
hook,Filters
andChips
are destructured and used directly in the component calling the hook.
In the current implementation, we are using queryParams from the URL as our single source of truth. SearchBox
will pass a common function for updating the URL to each Filter.
Here is the code I have come up with:
import React, { useState, useEffect } from "react"; import Chip from "@material-ui/core/Chip"; import HighlightOffIcon from"@material-ui/icons/HighlightOff"; type Filter = JSX.Element; type SBparams = { [key: string]: string | number; offset?: number; orderBy?: string; }; export function useSearchBox( filters: Filter[], updateParams: (params: any) => void, params: SBparams = {}): any { const [chipFilters, setChipFilters] = useState(filters); const [chips, setChips] = useState<JSX.Element[]>(); useEffect(() => { const deleteParam = (param: string) => { const newParams = Object.assign({}, params); delete newParams[param]; updateParams(newParams); }; const makeChips = (params: SBparams): JSX.Element[] => { const { offset, orderBy, ...relevantParams } = params; const newChips: JSX.Element[] = []; for (const [param, value] of Object.entries(relevantParams)) { const chip = ( <Chip color="primary" label={`${param}: ${value}`} deleteIcon={<HighlightOffIcon />} onDelete={() => deleteParam(param)} key={param} /> ); newChips.push(chip); } return newChips; }; const handleParamChange = (param, value) => { if (value == "" || value == null) { return deleteParam(param); } const newParams = Object.assign({}, params); newParams[param] = value; updateParams(newParams); }; const mappedFilters = chipFilters.map((filter: Filter) => { filter = React.cloneElement(filter, { handleParamChange: handleParamChange, }); return filter; }); setChipFilters(mappedFilters); setChips(makeChips(params)); }, [params]); return { filters: chipFilters, chips: chips }; }
submitted by /u/its4thecatlol
[link] [comments]