I am trying to set an active class on child component B while disabling the active class on child component A when I click on B.
So far I have tried using hooks in the parent class where I unset the active prop on all childs by using setActive('');
followed by setting the class of the current target to link--active by using e.currentTarget.className === 'link--active' ? e.currentTarget.className = '' : e.currentTarget.className = 'link--active';
. Sadly all it does at this moment is add the class or remove the class on the clicked child.
Parent:
const [active, setActive] = useState('');
const navigate = (e) => {
setActive('');
e.currentTarget.className === 'link--active' ? e.currentTarget.className = '' : e.currentTarget.className = 'link--active';
};
and in the return statement:
{menuItems.map((item, index) => (
<li key={index} >
<NavLink target={item} onClick={(e) => navigate(e)} active={active} />
</li>
))}
Children:
<a href="#"
onClick={props.onClick}
className={props.active}>
{props.target}
</a>
Edit:
After using the solution from Ori Drori, the active class was set on the clicked NavLink and removed from the rest. Since I wanted the onClick to be the navigate function, all I changed was set the onClick in the parent to navigate and have the navigate function call setActive by using id as param and calling setActive in the navigate function with id as a param again. The classes now look like this:
Parent:
const [active, setActive] = useState(null);
const navigate = (id) => {
setActive(id);
};
return (
{menuItems.map((item) => (
<li key={item.id} >
<NavLink
{...item}
isActive={active === item.id}
onClick={navigate} />
</li>
))}
)
Child:
const NavLink = ({id, target, isActive, onClick}) => {
return (
<a href="#"
onClick={useCallback(() => onClick(id), [id, onClick])}
className={isActive ? 'active' : ''}>
{target}
</a>
);
}
Pass setActive
to the NavLinks. When a NavLink
is clicked it sets it's id
via setActive
. Each item also receives the isActive
property, which is true
if the active
state matches it's id
.
const { useCallback, useState } = React
const NavLink = ({ id, target, isActive, onClick }) => (
<a href="#"
onClick={useCallback(() => onClick(id), [id])}
className={`navLink ${isActive ? 'active' : ''}` }>
{target}
</a>
)
const Parent = ({ menuItems }) => {
const [active, setActive] = useState(null);
return (
<ul>
{menuItems.map((item) => (
<li key={item.id} >
<NavLink
{...item}
onClick={setActive}
isActive={active === item.id} />
</li>
))}
</ul>
)
}
const items = [{ id: 0, target: 'Ready' }, { id: 1, target: 'Player' }, { id: 2, target: 'One' }]
ReactDOM.render(
<Parent menuItems={items} />,
demo
)
.navLink {
color: blue;
text-decoration: none;
}
.active {
color: red;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="demo"></div>