Home > Net >  How can I access a specific element's class name using useRef() to add/remove that class name?
How can I access a specific element's class name using useRef() to add/remove that class name?

Time:10-16

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>

  • Related