web-dev-qa-db-fra.com

Comment basculer la classe dans le composant imbriqué dans ReactJS

J'ai une telle méthode render () dans mon composant racine:

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>
    );
}

Où je veux basculer la classe 'active' entre les composants QuestionA et QuestionB lorsque l'utilisateur a cliqué sur le bouton. Comment puis-je faire ceci? Gardez à l'esprit que QuestionA et QuestionB ont leurs propres classNames dans leurs méthodes render (). Par exemple, render de QuestionB:

render: function() {
    return (
        <section className="question-b-container">
            ...
        </section>
    );
}
19
kirill.buga

Il y a plusieurs façons de gérer cela.

Si vous voulez que le parent contrôle la classe supplémentaire, vous pouvez simplement le transmettre aux composants enfants et leur demander de l'ajouter à leur nom de classe existant ( 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' });
  }
});

Cependant, il est probablement plus logique de laisser l’enfant gérer le nom de la classe et d’envoyer simplement des données pour indiquer s’il doit définir sa classe active ( 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' });
  }
});
22
Michelle Tilley

Comme Brian Voelker l'a mentionné dans comments , la manière désormais officielle de manipuler les classes dans React consiste à utiliser l'utilitaire classnames .

Vous pouvez définir vos deux composants comme suit:

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>
    )
  }

}

Et passez-leur simplement un accessoire active pour basculer la classe homonyme.

7
Balthazar

J'ai eu un problème semblable à celui-ci, j'ai créé un tiroir à onglets et je ne rendais que le composant demandé avec le tabber, mais une telle solution n'était pas idéale car je perdais l'état du composant enfant à chaque fois que je passais à un autre avec le tabber.

Pour éviter cela dans le rendu, j'appelle une fonction pour rendre tous mes enfants. Dans cette fonction, je place chaque enfant dans une div et j'attribue le nom de classe nécessaire à la div. Dans mon cas, je devais afficher un seul composant à la fois afin que je utilisait display: block ou none en fonction du bouton cliqué.

renderMyChilds() {
        var renderedComponents = this.props.children.map(function(child, _key) {
            if(this.state.drawerOpened == true) {
                var ElementToRender = child;
                var MyElement = (this.state.buttonSelected != _key) ? <div className="hiddenComponent"><ElementToRender /></div> : <div><ElementToRender /></div>;

            } else {
                var ElementToRender = child;
                var MyElement = <div><ElementToRender className="hiddenComponent" /></div>;
            }
            return (MyElement);
        }, this);
        return renderedComponents;
    }

.hiddenComponent { affichage: aucun; }

.visibleComponent { bloc de visualisation; }

0
CarCarlo