I have a SideBar component that has a sub component called SideBarLink which directs to the correct page.
I am trying add search functionality to my sidebar with a text field.
I have added a text input to the SideBar component and I am trying to figure out the best way to hide the SideBarLink components based on the match between the search text and text prop of the SideBarLink.
This is my current design for the side bar but it feels ugly to declare the hidden event on every SideBarLink when we already know the text prop (especially when I start adding many more links).
import "./SideBar.css";
import React, { useState } from "react";
import SideBarDropdown from "./SideBarDropdown";
import SideBarLink from "./SideBarLink";
import { TextInput } from "../Input";
const SideBar: React.FC = () => {
const [searchPhrase, setSearchPhrase] = useState<string>();
const acroynym = (str: string) =>
str
.split(/\s/)
.reduce((response, word) => (response += word.slice(0, 1)), "");
const match = (text: string) =>
searchPhrase
? text.toLowerCase().includes(searchPhrase?.toLowerCase()) ||
acroynym(text).toLowerCase().includes(searchPhrase?.toLowerCase())
: true;
return (
<nav id="sidebar" className="custom_scrollbar">
<ul className="list-unstyled components">
<TextInput
value={searchPhrase}
onChange={(value: string) => setSearchPhrase(value!)}
/>
<SideBarLink
to={`${urls.accounts}`}
text="Account"
icon="fas fa-plus-square"
hidden={!match("Account")}
/>
<SideBarLink
to={`${urls.customers}`}
text="Customer"
icon="fas fa-plus-square"
hidden={!match("Customer")}
/>
<SideBarLink
to={`${urls.orders}`}
text="Order"
icon="fas fa-plus-square"
hidden={!match("Order")}
/>
</ul>
</nav>
);
};
export default SideBar;
Is this the best approach for updating all the child components?
If you want a quick & dirty way, just pass the search text to the SideBarLink & declare your isMatch function there (you should also consider memoizing your function so it doesn't get redeclared after every render)
But I don't like this approach, because your SideBarLink being shown or not, has nothing to do with the SideBarLink itself. it's part of the rendering logic in your sidebar component so it should stay there. in order to do that just define all your links in an array & just map over it. like this:
const links = useMemo(() => [
{ text: 'Account', to: `${urls.accounts}`, icon: 'fas fa-plus-square' },
{ text: 'Customer', to: `${urls.customers}`, icon: 'fas fa-plus-square' },
], []);
then in your render loop over the array:
{links.map(({ text, to, icon }) => (
<SideBarLink
text="Customer"
to={`${urls.customers}`}
icon="fas fa-plus-square"
isMatch={isMatch(text)}
/>
))}
also don't forget to memoize your isMatch function:
const isMatch = useCallback(
(text: string) =>
searchPhrase
? text.toLowerCase().includes(searchPhrase?.toLowerCase()) ||
acroynym(text).toLowerCase().includes(searchPhrase?.toLowerCase())
: true,
[searchPhrase],
);