В настоящее время я создаю многоуровневое меню боковой панели в REACT, и я хочу динамически добавлять активный класс в родительский <li>, когда активен текущий маршрут.
В приведенном ниже коде показано, как я это делаю для одного меню.
<Route
path = {this.props.to}
exact = {this.props.activeOnlyWhenExact}
children = {({ match }) => (
<li className = {match ? "active" : ""}>
<Link to = {this.props.to} activeClassName = "active">
<span className = "sidebar-mini-icon">
<i className = {this.props.icon}></i></span>
{this.props.label}
</Link>
</li>
)}
/>
Теперь интересно, как у меня это получается с многоуровневым меню. Мое меню выглядит так;
Как видите, активный класс есть только в меню. Вот мой код для многоуровневого меню:
<Route
path = {this.props.to}
exact = {this.props.activeOnlyWhenExact}
children = {({ match }) => (
<li>
<a data-toggle = "collapse" href = "#Collapse">
<span className = "sidebar-mini-icon">
<i className = {this.props.icon}></i>
</span>
<span className = "sidebar-normal">
{this.props.name}
<b className = "caret"></b>
</span>
</a>
<div class = "collapse" id = "Collapse">
<ul className = "nav">
{this.props.children}
</ul>
</div>
</li>
)}
/>
Я использую React Router. Любая помощь будет оценена по достоинству. Спасибо.
@Sonson Ixon, ответили на ваш вопрос?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Моим первым побуждением было бы добавить className = {match ? "active" : ""} к родительскому li, но, поскольку вы спрашиваете об этом, я предполагаю, что вы уже пробовали это.
Вы можете покопаться в детском реквизите, чтобы узнать, есть ли у кого-нибудь из них реквизит match (или любой другой реквизит, который указывал бы, что они активны). Следующая функция может найти опору match у детей.
const childMatch = children => {
if (!children) { return false }
if (Array.isArray(children)) {
return children.reduce(
(acc, child) => acc || Boolean(child.props.match),
false
)
}
return Boolean(children.props.match)
}
Затем вы можете использовать его как className = {childMatch(this.props.children) ? "active" : ""}.
Если объект, который вы ищете, находится глубже в дереве детей, вы, конечно, можете копнуть глубже. Вы можете найти внуков как child.props.children.
Это не сработало. Но спасибо за ответ. Оценил.
Вы можете использовать Навигационная ссылка маршрутизатора React
<NavLink to = "/faq" activeClassName = "selected">
FAQs
</NavLink>
это было бы для одного меню, мы хотим добавить класс в родительское меню
Нет, это не имеет зависимости. Если вы находитесь на пути к, он добавит activeClassName. У него нет родительской и дочерней зависимости.
Вы можете использовать ловушку useLocation.
С помощью ловушки useMemo вы можете запускать функцию всякий раз, когда изменяется местоположение. Таким образом вы добавляете класс к активному родительскому элементу при каждом изменении местоположения.
Но вам нужно убедиться, что вызов useLocation не находится в том же компоненте, который помещает маршрутизатор в DOM.
Итак, в корневом индексном файле или каком-либо другом компоненте вы можете иметь что-то вроде этого
import { useLocation, useEffect } from "react-router-dom";
const Item = () => {
const location = useLocation();
// Select the nav item with the active class, and add the extra class to its parent
useMemo(() => document.querySelector(activeClassName)?.parentElement?.classList.add(activeParentClassName), [location])
return (...);
}
Это основано на предположении, что сгруппированные маршруты имеют идентичный начальный маршрут, такой как /a/b/c и a/b/e.
Пункт многоуровневого меню должен выглядеть так.
Ярлык группы должен иметь собственный Route, он не должен быть точным и должен иметь путь, который делает его родительским каталогом для фактических ссылок меню.
<li>
<Route
path = "/a"
children = {({ match }) => (
<a data-toggle = "collapse" href = "#Collapse" className = {match ? 'active' : ''}>
...
</a>
)}
/>
И тогда фактические элементы ссылок в меню должны быть точными и иметь путь, который делает его подкаталогом к первому ключу.
<ul>
<Route
exact
path = "/a/b"
children = {({ match }) => (
<li className = {match ? "active" : ""}>
<Link to = {this.props.to} activeClassName = "active">
{/* ... */}
</Link>
</li>
)}
/>
{/* other routes */}
</ul>
Вам не нужно использовать здесь селекторы useEffect или Dom, выясните, должны ли быть активными группа и ссылка (максимум useMemo, который является синхронным), и извлеките из них правильные классы (передавая как опору, если необходимо) в JSX из тот же или более высокий уровень в дереве. Доступ к DOM предназначен для редких случаев использования, и запись в DOM в дереве реакции всегда неверна.
Решение будет зависеть от конфигурации вашего маршрута. Если вы используете неточные маршруты, решение с NavLink будет наиболее подходящим.
Пример:
routes.jsx
<Route path = "/parent/child-a">
<ChildA />
</Route>
<Route path = "/parent/child-b">
<ChildB />
</Route>
<Route path = "/parent">
<Parent />
</Route>
Используя приведенную выше структуру, /parent/child-a будет соответствовать двум маршрутам (/parent и /parent/child-a), а опора activeClassName на NavLink будет применяться к обоим элементам HTML.
«Проблема» с приведенной выше структурой заключается в том, что вы собираетесь рендерить <Parent /> во всех трех случаях.
Это можно решить, используя вложенные / дочерние маршруты.
routes.jsx
<Route path = "/parent">
<NestedRoutes />
</Route>
nestedRoutes.jsx
<Route path = "/parent/child-a" exact>
<ChildA />
</Route>
<Route path = "/parent/child-b" exact>
<ChildB />
</Route>
С обновленной структурой, приведенной выше, /parent/child-a будет соответствовать маршруту верхнего уровня (и в результате добавить activeClassName к вашему элементу HTML), а также сопоставить дочерний маршрут и добавить туда activeClassName.
Обратите внимание, что если вам нужно, чтобы /parent также работал в качестве маршрута, вам необходимо обновить вложенные маршруты следующим образом:
nestedRoutes.jsx
<Route path = "/parent" exact>
<Parent />
</Route>
По моему опыту, если вы обнаружите, что обрабатываете эти случаи вручную с помощью JavaScript или useLocation, вам может потребоваться пересмотреть конфигурацию маршрута. react-router - отличная библиотека благодаря своей простоте и, вероятно, справится с вашим случаем сразу после установки.
Это большой вопрос!
Если я правильно понимаю, есть желание динамически добавить активный класс к элементу li, если текущий маршрут совпадает.
Для этого давайте создадим новый компонент под названием NavListItem. NavListItem проверит, соответствует ли текущий маршрут его опоре to. Если это так, он отобразит activeClassName. Это мало чем отличается от компонента NavLink response-router-doms. За исключением того, что мы будем отображать li вместо ссылки.
NavListItem.js
import React from 'react';
import { useLocation, matchPath } from 'react-router-dom';
export const NavListItem = ({
path,
exact,
sensitive,
strict,
activeClassName = 'active',
className,
children,
...otherProps
}) => {
const location = useLocation();
const match = matchPath(location.pathName, {
path: path,
exact: exact,
sensitive: sensitive,
strict: strict,
});
const isActive = Boolean(match);
const className = isActive ? [activeClassName, className].join(' ') : className;
const props = {
className: className,
...otherProps,
};
return <li {...props}>{children}</li>;
};
И вот использование вашего примера кода.
<NavListItem path = {this.props.to} exact = {this.props.activeOnlyWhenExact}>
<a data-toggle = "collapse" href = "#Collapse">
<span className = "sidebar-mini-icon">
<i className = {this.props.icon}></i>
</span>
<span className = "sidebar-normal">
{this.props.name}
<b className = "caret"></b>
</span>
</a>
<div class = "collapse" id = "Collapse">
<ul className = "nav">{this.props.children}</ul>
</div>
</NavListItem>
По вашему вопросу. Я бы посоветовал использовать навигационную ссылку маршрутизатора React
<NavLink to = "/<route-name>" activeClassName=<classname>>
Title
</NavLink>
Я тоже ищу аналогичный ответ. Пожалуйста, помогите кому-нибудь.