I think this is not an ideal way of doing filters. I have to type more if else's and it doesn't look good.
I found a package called "useFilter". but can I just make it without using any packages? like with hooks or something.
import { AddPosition } from "./../../data/careers/AddPosition";
const Positions = () => {
const [positions] = useState(AddPosition);
const [searchTerm, setSearchTerm] = useState("");
<input
type="search"
placeholder="Search"
onChange={(e) => setSearchTerm(e.target.value)}
/>
{positions
.filter((position) => {
if (searchTerm === "") {
return position;
} else if (
position.category
.toLowerCase()
.includes(searchTerm.toLowerCase())
) {
return position;
} else if (
position.type.toLowerCase().includes(searchTerm.toLowerCase())
) {
return position;
} else if (
position.location
.toLowerCase()
.includes(searchTerm.toLowerCase())
) {
return position;
} else if (
position.position
.toLowerCase()
.includes(searchTerm.toLowerCase())
) {
return position;
}
})
.map((position) => (
<>
<SinglePosition
id={position.id}
category={position.category}
type={position.type}
position={position.position}
/>
</>
))}
</div>
</div>
</div>
CodePudding user response:
You can simplify this by using Array.prototype.some
and you can also use useMemo
to make sure that the filtering happens only when positions
/searchTerm
changes.
const filteredPositions = useMemo(() => {
if(!searchTerm) return positions;
const lowerCasedSearchTerm = searchTerm.toLowerCase();
return positions.filter(({id, ...other}) => {
// assuming you want to check every value in position
return Object.values(other).map(v => v.toLowerCase()).some(v => v.includes(lowerCasedSearchTerm))
})
}, [positions, searchTerm])
Now you can map filteredPositions
in the JSX.
CodePudding user response:
You're logic is repeated for each property of position
. Combine them to a single array, and iterate it with Array.some()
if any of the includes the term, it would return true:
{positions
.filter(({ id, ...rest }) => {
const term = searchTerm.toLowerCase();
return !term || Object.values(rest).some(str =>
str.toLowerCase().includes(term)
);
})
.map(position => (
<SinglePosition key={position.id} {...position} />
))
}
Note: when rendering a list of items don't forget to include a key
property. In addition, you don't need to wrap a single element in a fragment. You need a fragment only if you render multiple elements without a single parent.