I have this jQuery snippet below
$("#navbarSupportedContent").on("click", "li", function (e) {
$("#navbarSupportedContent ul li").removeClass("active");
$(this).addClass("active");
});
I'm trying to convert the above snippet into React.js code. However, it's incorrect. I can't even get passed the removing active
class part, which's the first line in the above snippet.
const tabsNewAnimRef = useRef(null);
const horiSelectorRef = useRef(null);
const activeItemNewAnimRef = useRef(null);
tabsNewAnimRef.current.addEventListener("click", () => {
let children = tabsNewAnimRef.current.children;
// Convert an HTMLCollection to an Array
let array = [...children];
let childrenArray = array[0].children;
console.log(childrenArray[2].classList[1].remove('active'));
});
<div className="collapse navbar-collapse" id="navbarSupportedContent" ref={tabsNewAnimRef}>
<ul className="navbar-nav ml-auto">
<div className="hori-selector" ref={horiSelectorRef}>
<div className="left"></div>
<div className="right"></div>
</div>
<li className="nav-item" ref={activeItemNewAnimRef}>
<a className="nav-link" href="javascript:void(0);"><i className="fas fa-tachometer-alt"></i>Dashboard</a>
</li>
<li className="nav-item active" ref={activeItemNewAnimRef}>
<a className="nav-link" href="javascript:void(0);"><i className="fas fa-house-user"></i>Home</a>
</li>
<li className="nav-item" ref={activeItemNewAnimRef}>
<a className="nav-link" href="javascript:void(0);"><i className="far fa-clone"></i>Components</a>
</li>
<li className="nav-item" ref={activeItemNewAnimRef}>
<a className="nav-link" href="javascript:void(0);"><i className="far fa-calendar-alt"></i>Calendar</a>
</li>
</ul>
</div>
I've tried looking up various possible ways to do this but I keep running into ealls. How can I achieve this?
CodePudding user response:
It seems like useState would be appropriate for handling whether active
is relevant or not. Something like this...
const [active, setActive] = useState(true);
<div id="navbarSupportedContent" onClick={() => setActive(!active);}>
<ul>
<li className={active ? "active" : ""}>...</li>
</ul>
</div>
I think you can probably get away without using useRef at all.
CodePudding user response:
Forget about using useRef
- it won't do much good in this example. You need to be storing the active status of your list items in state.
In this example, to make things a little easier, there is a config array of objects that we initialise state with - all the items' active props are set to false
. We can then use this array in state to build the list items in the JSX by mapping
over each object and creating an element with the nav-item
class as well as an active class if that prop has been updated in the state when an item is clicked.
const { useState } = React;
// Pass in the config
function List({ config }) {
// Initialise state with it
const [ items, setItems ] = useState(config);
// When a list item is clicked we grab its `id`,
// and create a new array of object by mapping over the
// existing state. In the `map` callback we return an object
// with an updated active prop depending on whether the id of the
// object matches that id. Then we update the state with the new
// array
function handleClick(e) {
const { id } = e.target.dataset;
const reset = items.map(item => {
return {
...item,
active: item.id === id ? true : false
};
});
setItems(reset);
}
// `map` over the items state, create a class using
// `nav-item` and `active`, and then apply each item's
// properties to the element. Finally add a click listener
// to the element which calls the `handleClick` function.
return (
<ul>
{items.map(item => {
const cn = [
'nav-item',
item.active && 'active'
].join(' ');
return (
<li
key={item.id}
data-id={item.id}
className={cn}
onClick={handleClick}
>{item.text}
</li>
);
})}
</ul>
);
}
const config = [
{ id: 1, text: 'Dashboard', active: false },
{ id: 2, text: 'Home', active: false },
{ id: 3, text: 'Components', active: false },
{ id: 4, text: 'Calendar', active: false }
];
ReactDOM.render(
<List config={config} />,
document.getElementById('react')
);
ul { list-style: none; margin-left: 0px; padding-left: 0px; }
.nav-item { padding: 0.25em; }
.nav-item:hover { cursor: pointer; }
.nav-item:not(.active):hover { background-color: #efefef; }
.active { background-color: lightgreen; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>