6

I've been working on React for a few weeks now, and while I've got most of the basic syntax down (props, states), I'm struggling to draw some connections with some concepts, most notably adding classes when a state has changed. I'm trying to build a simon says game, which contains four buttons, all built using a Button component. These are initially set to have a opacity of .3 and an active state of false. When clicked, the state "active" becomes true, but I cannot for the life of me figure out how to add a css class that can give the button a full opacity. Here is my code:

class App extends Component {
  constructor(){
    super();
    this.state = {
      active: false
    }
  }
  handleClick(){
    this.setState({active: !this.state.active})
  }
  renderButtons(i, f){
    return <Button value={i} className="button" id={f} active= {this.state.active} onClick={() => this.handleClick()}/>
  }
  render() {
    return (
      <div className="App">
        {this.renderButtons("red", "buttonRed")}
        {this.renderButtons("blue", "buttonBlue")}
        {this.renderButtons("green", "buttonGreen")}
        {this.renderButtons("yellow", "buttonYellow")}
      </div>
    );
  }
}

And my css:

.button{
  width: 100px;
  height: 45px;
  opacity: .3;
  margin: 0 auto;
  margin-bottom: 30px;
}
#buttonRed{
  background: red;
}
#buttonBlue{
  background: blue;
}
#buttonGreen{
  background: green;
}
#buttonYellow{
  background: yellow;
}

So, at this moment, I would simply like to add a class when clicking the button while still keeping the "button" class to the component. Can anyone help?

4 Answers 4

11

React has a couple of ways of doing this. The first is as suggested by Tudor Ilisoi, which is simply concatenating strings. The second way is to give className an Object instead of a string. This way is arguably simpler but requires you to add the classnames module. You can install it with either npm install --save classnames or yarn add classnames. You can import it with:

import classNames from 'classnames';

And then you can use it in the following way:

<button className={classNames({button: true, active: this.state.active})} />

The first pair of curly brackets just tells react that we are passing a dynamic property, and the second is just the normal JavaScript syntax for objects. Note that the object is wrapped by the classNames() function. If we had declared it earlier, we could just as easily do:

render(){
    const classes = classNames({
        button: true, // we always want this class
        active: this.state.active, // only add this class if the state says so
     });

     return (
          <button className={classes} />
     );
}
Sign up to request clarification or add additional context in comments.

7 Comments

Thank you, this is a very thorough explanation! I'm assuming you can pass as many key/value pairs into the className object as you want? And just so I'm understanding correctly, Button will have one class of 'button' when this.state.active is false, but two classes 'button' and 'active' when this.state.active is true?
What if the classes have hyphens? I'm not allowed to do {red-button: true}.
As a matter of fact, I have hard time getting this to work with any class name: const valueSpan = <span className={{small: true}}>label</span>; renders as <span class="[object Object]">label</span>
@steve, I have edited the answer. You should be able to see it online in a while, just after the peer review. Hope it helps, cheers!
@steve it's online
|
3

if you are looking for 2021/2022 answer: Here is an example that uses react hooks, which add the class name app to a div element when we click on a Toggle class button.

 import React, { useState } from "react";import "./styles.css";

export default function App() {
  const [isActive, setActive] = useState("false");
  const handleToggle = () => {
    setActive(!isActive);  };
  return (
    <div className={isActive ? "app" : null}>
       <h1>Hello react</h1>
       <button onClick={handleToggle}>Toggle class</button>
    </div>
  );
}

1 Comment

Please don't add "thank you" as an answer. Once you have sufficient reputation, you will be able to vote up questions and answers that you found helpful. - From Review
1

change className="button" to className={'button ' + f}

The expression enclosed in curly braces is evaluated as javascript and it produces a string

Also note that when using the curly brace syntax you do not have to add double quotes "" around attribute value .

When your JSX is parsed, React will generate the proper HTML attribute, for example class="button red".

Comments

0

Have you tried, pass an optional parameter to renderButtons, check it and add to class :

...
 renderButtons(i, f, c){
    var cssClass =  c&&c!=""? "button " + c : "button";   
    return <Button value={i} className={cssClass}  id={f} active= {this.state.active} onClick={() => this.handleClick()}/>
  }
...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.