Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to toggle class in the nested component in ReactJS

I have such render() method in my root component:

render: function() {
    return (
        <div className="question">
            <QuestionA question={this.props.question} author={this.props.author}/>
            <QuestionB yes={this.state.yes} no={this.state.no} />
            <div className="question-side-switcher" onClick={this.handleSideChanging}></div>
        </div>
    );
}

Where I want to toggle the 'active' class between QuestionA and QuestionB components when user clicked the button. How can I do this? Keep in mind, that QuestionA and QuestionB are set their own classNames in their render() methods. For example QuestionB's render():

render: function() {
    return (
        <section className="question-b-container">
            ...
        </section>
    );
}
like image 253
kirill.buga Avatar asked Apr 12 '14 09:04

kirill.buga


People also ask

How do you toggle between classes in React?

To toggle class on click with React, we can set the className prop. to create the MyComponent component. In it, we have the isActive state. We set it with the setActive function in the toggleClass function.

How do you toggle a component in React?

Replace the contents of src/ToggleSwitch/ToggleSwitch. js with the following: import React from "react"; import PropTypes from "prop-types"; import './ToggleSwitch. scss'; /* Toggle Switch Component Note: id, checked and onChange are required for ToggleSwitch component to function.

Can props in React be changed inside the component?

A component cannot update its own props unless they are arrays or objects (having a component update its own props even if possible is an anti-pattern), but can update its state and the props of its children.


2 Answers

There are a couple ways you could handle this.

If you want the parent to control the additional class, you can simply pass it in to the child components and have them add it to their existing class name (JSFiddle demo):

var QuestionA = React.createClass({
  render: function() {
    return <section className={this.props.className + " question-a-container"}>Section A</section>;
  }
});

var QuestionB = React.createClass({
  render: function() {
    return <section className={this.props.className + " question-b-container"}>Section B</section>;
  }
});

var Root = React.createClass({
  getInitialState: function() {
    return { question: 'a' };
  },

  render: function() {
    var qAclassName = this.state.question === 'a' ? 'active' : '';
    var qBclassName = this.state.question === 'b' ? 'active' : '';
    return (
      <div className="question">      
        <QuestionA className={qAclassName} />
        <QuestionB className={qBclassName} />
        <div className="question-side-switcher" onClick={this.handleSideChanging}>Change</div>
      </div>
    );
  },

  handleSideChanging: function() {
    this.setState({question: this.state.question === 'a' ? 'b' : 'a' });
  }
});

However, it probably makes more sense to let the child manage the class name, and simply send some data along to indicate if it should set its active class (JSFiddle demo):

// Using classSet to more easily create conditional class names;
// see http://facebook.github.io/react/docs/class-name-manipulation.html
var cx = React.addons.classSet;

var QuestionA = React.createClass({
  render: function() {
    // always set "question-a-container";
    // set "active" if we got a truthy prop named `active`
    var className = cx({
      "question-a-container": true,
      "active": this.props.active
    });
    return <section className={className}>Section A</section>;
  }
});

var QuestionB = React.createClass({
  render: function() {
    // always set "question-b-container";
    // set "active" if we got a truthy prop named `active`
    var className = cx({
      "question-b-container": true,
      "active": this.props.active
    });
    return <section className={className}>Section B</section>;
  }
});

var Root = React.createClass({
  getInitialState: function() {
    return { question: 'a' };
  },

  render: function() {
    return (
      <div className="question">
        {/* For each question, compare to state to see if it's active. */}
        <QuestionA active={this.state.question === 'a'} />
        <QuestionB active={this.state.question === 'b'} />
        <div className="question-side-switcher" onClick={this.handleSideChanging}>Change</div>
      </div>
    );
  },

  handleSideChanging: function() {
    this.setState({question: this.state.question === 'a' ? 'b' : 'a' });
  }
});
like image 67
Michelle Tilley Avatar answered Sep 27 '22 20:09

Michelle Tilley


As Brian Voelker mentioned it in the comments, the now official way to manipulate classes in React is to use the classnames utility.

You could define your two components like so:

import React, { Component } from 'react'
import classNames from 'classnames'

class QuestionA extends Component {

  render () {

    const { active } = this.props
    const cx = classNames('question-a-container', { active })

    return (
      <section className={cx}></section>
    )
  }

}

And simply pass them an active prop to toggle the namesake class.

like image 20
Preview Avatar answered Sep 27 '22 21:09

Preview