There is a nested menu in React Bootstrap and it's working fine except the active collapsible is not open by default. I need to change the in
attribute's value in the Collapse
to make it work, but only for the active page. I thought I can use hasActiveChild
, but I'm not sure how to add into useEffect
properly.
I only added the important part of the code, I just basically return with renderMenu
later in the code.
const { data, error, isLoading } = useSWR('/api/staticdata', fetcher);
const router = useRouter();
const currentRoute = router.pathname;
const renderMenu = (menu) => {
const [open, setOpen] = useState(menu.map(() => false));
const hasActiveChild = (currentItem) => currentItem.child.some(currentItem => currentItem.url === currentRoute);
useEffect(() => {
if (menu.length !== open.length) {
setOpen(menu.map(() => false));
}
}, [menu, open]);
return menu.map((item, index) => (
<Nav.Item className={item.child && "dropdown"} key={index}>
{item.url ?
<Nav.Link href={item.url} className={(currentRoute === item.url) && "active"}>
<span>{item.title}</span>
</Nav.Link>
:
<Nav.Link className={hasActiveChild(item) && "active"} onClick={() => {
setOpen((open) => open.map((o, i) => {
if (i === index) return !o;
return o;
}));
}} aria-controls={`collapse${capitalizeEachWord(item.title)}`} aria-expanded={open[index]} data-bs-toggle="collapse">
<span>{item.title}</span>
</Nav.Link>
}
{item.child && (
<Collapse in={open[index]} key={index} data-open={open[index]}>
<div id={`collapse${capitalizeEachWord(item.title)}`}>
<div className="nav flex-column">
{renderMenu(item.child)}
</div>
</div>
</Collapse>
)}
</Nav.Item>
))
}
If someone interested:
const [open, setOpen] = useState(
menu.map((m, i) => {
if(m.child) {
if(m.child.some(child => {return child.url === currentRoute})) return true;
}
})
);
useEffect(() => {
if (menu.length !== open.length) {
setOpen(menu.map(() => false));
}
}, [menu]);