简体   繁体   中英

How to iterate through DOM elements in react and add/remove classes?

I am beginner to react and I am unable to iterate through div elements.
Each of these div elements (shown in the code) have a common className="step" initially but once the button Next is clicked I want 1st div to have className="step current" . Once Next is clicked again 1st div element should have className="step done" (remove current and append done) and 2nd div element would have classname="step current"

I was able to toggle the className from "step" to "step current" in the following code but I am facing difficulty to traverse the div elements and add or remove the class.

 class NavBar extends React.Component{ state = { addClass : false } handleClick=()=>{ this.setState({addClass: !this.state.addClass}); } render(){ let arrowClass = ["step"]; if(this.state.addClass){ arrowClass.push("current"); } return( <div id="navbar-div"> <div className="arrow-steps clearfix"> 1. <div className={arrowClass.join(' ')}> <span> Step1</span> </div> 2. <div className={arrowClass.join(' ')}> <span>Step2</span> </div> 3. <div className={arrowClass.join(' ')}> <span> Step3</span> </div> 4. <div className={arrowClass.join(' ')}> <span>Step4</span> </div> 5. <div className={arrowClass.join(' ')}> <span>Step5</span> </div> </div> <div className="nav clearfix"> <a href="#" className="prev">Previous</a> <a href="#" className="next pull-right" onClick={this.handleClick}>Next</a> </div> </div> ); } } ReactDOM.render( <NavBar />, document.getElementById("root") );
 .current { font-weight: bold; } .done { color: #aaa; }
 <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>

The classes step, current and done are defined in the css file.

Rather than writing the steps explicitly, put them in an array, and then remember where you are within that array with an indexing variable. Here's the minimal-changes approach to doing that with your code (see comments):

 class NavBar extends React.Component{ state = { steps: ["Step1", "Step2", "Step3", "Step4"], current: 0 // <== Step1 is the current step } prevClick = () => { // Move to previous step, note we use the callback version of setState, // see https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous this.setState(({current}) => ({current: Math.max(0, current - 1)})); } nextClick = () => { // Move to next step this.setState(({steps, current}) => ({current: Math.min(steps.length - 1, current + 1)})); } render() { // Get the steps and the current index const {current, steps} = this.state; // Render them, checking the position of the step (`index`) relative to `current` // and outputting the relevant class name. // I changed your `div`s to an ordered list so we get automatic numbering return ( <div id="navbar-div"> <div>{current}</div> <ol className="arrow-steps clearfix"> {steps.map((step, index) => <li key={index} className={`step ${index < current ? 'done' : index == current ? 'current' : ''}`}>{step}</li> )} </ol> <div className="nav clearfix"> <a href="#" className="prev" onClick={this.prevClick}>Previous</a> <a href="#" className="next pull-right" onClick={this.nextClick}>Next</a> </div> </div> ); } } ReactDOM.render( <NavBar />, document.getElementById("root") );
 .current { font-weight: bold; } .done { color: #aaa; }
 <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>

Obviously, that just shows the basic approach, you'll want to modify it. If you have any information other than just the step text, you might make the array entries objects rather than just strings.

(Note: Using index as the key on those li s is only valid if you don't add/remove entries in the array of steps.)


Side note: As Murali Krishna pointed out , you had class rather than className on the div containing the previous/next links and on those links; I've changed those to className above.

Although you can do that but there's a more React'ish way. That is to use state to store the class you wanna add. So when you change the state (using setState) it will auto re-render and set the class.

Eg.

class NavBar extends React.Component{
    state = {
        status: "current"
    }
    handleClick=()=>{
        this.setState(prevState=>{
            if(prevState.status === 'current'){
                return {status:"done"}
            }else{
                return {status:"current"}
            }
        })

    }
    render(){
        return <button className={"step " + this.state.status} onClick={this.handleClick}>Hello</button>
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM