Search code examples
reactjsjsxdom-manipulation

Using document.classlist.remove in react


When I click on a new li tag, I want the classname to change to active (which works), but also remove active from the rest of the li tags (which doesn't work). document.getElementByTagName('li').classList.remove="active", doesn't work because it is saying it is not defined. Should I go about this a different way... maybe storing something different in the state?

import React, {useState, useEffect} from 'react';
import './Anime.css';

function Anime(){
    const [currentCase, setCurrentCase] = useState(0)
    function getAnime(){
        fetch('https://kitsu.io/api/edge/anime')
        .then(response => response.json())
        .then(data => console.log(data));
    }

    function currentSelector(e){
        document.getElementsByTagName('li').clasList.remove("active");
        setCurrentCase(e.target.value)
        e.target.className = "active" 
    }

    useEffect(() => {
        getAnime();
      }, []);
    
    return(
        <div className="anime">
            {/* Selectors */}
            <ul>
                <li value= {0} className="active" onClick={currentSelector}>Trending</li>
                <li value={1} onClick={currentSelector}>Action</li>
                <li value={2} onClick={currentSelector}>Adventure</li>
                <li value={3} onClick={currentSelector}>Comedy</li>
                <li value={4} onClick={currentSelector}>Drama</li>
                <li value={5} onClick={currentSelector}>Magic</li>
                <li value={6} onClick={currentSelector}>Romance</li>
            </ul>
            
        </div>
    )
}

export default Anime

Solution

  • Don't use the usual DOM API for things like this in React, instead use React's state management and conditional rendering functionality. You already have a state variable to track the active case (currentCase), so you can just set the class name conditionally while rendering.

    For each li, just check if the value of currentCase matches the value for that li and if so, give that li the class active, otherwise give a different class.

    For example:

    import React, {useState, useEffect} from 'react';
    import './Anime.css';
    
    function Anime(){
        const [currentCase, setCurrentCase] = useState(0)
        function getAnime(){
            fetch('https://kitsu.io/api/edge/anime')
            .then(response => response.json())
            .then(data => console.log(data));
        }
    
        function currentSelector(e){
            setCurrentCase(Number(e.target.value));
        }
    
        useEffect(() => {
            getAnime();
          }, []);
        
        return(
            <div className="anime">
                {/* Selectors */}
                <ul>
                    <li value={0} className={currentCase === 0 ? "active" : ""} onClick={currentSelector}>
                        Trending
                    </li>
                    <li value={1} className={currentCase === 1 ? "active" : ""} onClick={currentSelector}>
                        Action
                    </li>
                    <li value={2} className={currentCase === 2 ? "active" : ""} onClick={currentSelector}>
                        Adventure
                    </li>
                    <li value={3} className={currentCase === 3 ? "active" : ""} onClick={currentSelector}>
                        Comedy
                    </li>
                    <li value={4} className={currentCase === 4 ? "active" : ""} onClick={currentSelector}>
                        Drama
                    </li>
                    <li value={5} className={currentCase === 5 ? "active" : ""} onClick={currentSelector}>
                        Magic
                    </li>
                    <li value={6} className={currentCase === 6 ? "active" : ""} onClick={currentSelector}>
                        Romance
                    </li>
                </ul>
                
            </div>
        )
    }
    
    export default Anime
    

    Or extract the class name logic into a function (defined within your Anime component) and call that function for each li element:

    function getLiClassName(value) {
        if (value === currentCase) {
            return "active";
        }
        return "";
    }
    

    And use like this:

    <li value={0} className={getLiClassName(0)} onClick={currentSelector}>
        Trending
    </li>