Reaja Js aplicando condicionalmente atributos de classe


334

Quero mostrar e ocultar condicionalmente esse grupo de botões, dependendo do que é passado do componente pai, que se parece com isso:

<TopicNav showBulkActions={this.__hasMultipleSelected} />

....

__hasMultipleSelected: function() {
  return false; //return true or false depending on data
}

....

var TopicNav = React.createClass({
render: function() {
return (
    <div className="row">
        <div className="col-lg-6">
            <div className="btn-group pull-right {this.props.showBulkActions ? 'show' : 'hidden'}">
                <button type="button" className="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
                  Bulk Actions <span className="caret"></span>
                </button>
                <ul className="dropdown-menu" role="menu">
                  <li><a href="#">Merge into New Session</a></li>
                  <li><a href="#">Add to Existing Session</a></li>
                  <li className="divider"></li>
                  <li><a href="#">Delete</a></li>
                </ul>
            </div>
        </div>
    </div>
    );
  }
});

Porém, nada está acontecendo com as {this.props.showBulkActions? 'show': 'oculto'}. Estou fazendo algo errado aqui?


Você também pode considerar o react-bootstrap , pois isso abstrai parte do material da classe nas propriedades do componente, facilitando um pouco o que você está tentando fazer.
21817 Dancrumb

Respostas:


590

Os chavetas estão dentro da string, portanto estão sendo avaliadas como string. Eles precisam estar fora, então isso deve funcionar:

<div className={"btn-group pull-right " + (this.props.showBulkActions ? 'show' : 'hidden')}>

Observe o espaço após "pull-right". Você não deseja fornecer acidentalmente a classe "pull-rightshow" em vez de "pull-right show". Também os parênteses precisam estar lá.


3
Obrigado! Eu tive que modificá-lo um pouco porque, por algum motivo, não estava exibindo o pull-btn-group. Apenas mostre ou oculto.
Apexdodge 29/05

Isso é particularmente útil em certos casos em que classnamespode não ser apropriado. Se você estiver em sua renderfunção e tiver um map, talvez só saiba se deseja adicionar uma classe no momento em que a estiver renderizando, portanto essa resposta é bastante útil para isso.
Dave Cooper

excelente alternativa em vez de ter um monte de modelos condicionais em sua render ou voltar
devonj

@apexdodge que modificação você teve que fazer. Eu tenho o mesmo problema.
RamY 06/06

1
@RamY Uma maneira é colocar todas as classes dentro do condicional this.props.showBulkActions ? 'btn-group pull-right show' : 'btn-group pull-right hidden'). Não é elegante, mas funciona.
Ian

87

Como outros comentaram, o utilitário classnames é a abordagem atualmente recomendada para lidar com nomes condicionais de classes CSS nos ReactJs.

No seu caso, a solução será semelhante a:

var btnGroupClasses = classNames(
  'btn-group',
  'pull-right',
  {
    'show': this.props.showBulkActions,
    'hidden': !this.props.showBulkActions
  }
);

...

<div className={btnGroupClasses}>...</div>

Como uma observação lateral, sugiro que você tente evitar o uso de ambos showe hiddenclasses, para que o código seja mais simples. Provavelmente você não precisa definir uma classe para que algo seja mostrado por padrão.


11
Você poderia elaborar o utilitário classNames como a "abordagem atualmente recomendada"? Isso é capturado em algum documento de boas práticas bem considerado em algum lugar? Ou apenas um tipo de palavra da boca em torno do React e classNamesno momento?
Alexander Nied

6
@anied No momento em que este documento foi escrito, era recomendado na documentação oficial do React: web.archive.org/web/20160602124910/http
Diego V

3
Ele ainda é mencionado na documentação mais recente : " Se você costuma escrever um código como este, o pacote classnames pode simplificá-lo. "
Franklin Yu

66

Se você estiver usando um transpiler (como Babel ou Traceur), poderá usar as novas " strings de modelo " do ES6 .

Aqui está a resposta de @ spitfire109, modificada de acordo:

<div className={`btn-group pull-right ${this.props.showBulkActions ? 'shown' : 'hidden'}`}>

Essa abordagem permite que você faça coisas legais como essa, renderizando s-is-shownou s-is-hidden:

<div className={`s-${this.props.showBulkActions ? 'is-shown' : 'is-hidden'}`}>

20
Cuidado com a segunda abordagem, especialmente em grandes bases de código, pois isso torna as seqüências de classes menos aceitáveis. Por exemplo, se alguém pesquisar s-is-shownou s-is-hiddenna base de código, não encontrará esse código.
marca de

15

Você pode usar aqui literais String

const Angle = ({show}) => {

   const angle = `fa ${show ? 'fa-angle-down' : 'fa-angle-right'}`;

   return <i className={angle} />
}

9

Gastando com a boa resposta de @ spitfire109, pode-se fazer algo assim:

rootClassNames() {
  let names = ['my-default-class'];
  if (this.props.disabled) names.push('text-muted', 'other-class');

  return names.join(' ');
}

e depois dentro da função de renderização:

<div className={this.rootClassNames()}></div>

mantém o jsx curto


8

Ou use nomes de classe npm . É muito fácil e útil, especialmente para construir a lista de classes


8

Caso você precise apenas de um nome de classe opcional:

<div className={"btn-group pull-right " + (this.props.showBulkActions ? "show" : "")}>

1
Isso acrescentará falseclasse quando a condição falhar.
RA.


5

2019:

React é um lago de muitos utilitários. Mas você não precisa de nenhum npmpacote para isso. basta criar em algum lugar a função classnamese chamá-la quando precisar;

function classnames(obj){
  return Object.entries(obj).filter( e => e[1] ).map( e=>e[0] ).join(' ');
}

ou

function classnames(obj){
 return Object.entries(obj).map( ([k,v]) => v?k:'' ).join(' ');
}

exemplo

  stateClass= {
    foo:true,
    bar:false,
    pony:2
  }
  classnames(stateClass) // return 'foo pony'

 <div className="foo bar {classnames(stateClass)}"> some content </div>

Just For Inspiration

declarar elemento auxiliar e usou o togglemétodo

(DOMToken​List)classList.toggle(class,condition)

exemplo:

const classes = document.createElement('span').classList; 

function classstate(obj){
  for( let n in obj) classes.toggle(n,obj[n]);
 return classes; 
}

4

Solução mais elegante, melhor para manutenção e legibilidade:

const classNames = ['js-btn-connect'];

if (isSelected) { classNames.push('is-selected'); }

<Element className={classNames.join(' ')}/>

3

você pode usar isso:

<div className={"btn-group pull-right" + (this.props.showBulkActions ? ' show' : ' hidden')}>

2

Isso funcionaria para você

var TopicNav = React.createClass({
render: function() {

let _myClasses = `btn-group pull-right {this.props.showBulkActions?'show':'hidden'}`;

return (
            ...
            <div className={_myClasses}>
               ...
            </div>
    );
  }
});

1

Você pode usar este pacote npm. Ele lida com tudo e tem opções para classes estáticas e dinâmicas com base em uma variável ou uma função.

// Support for string arguments
getClassNames('class1', 'class2');

// support for Object
getClassNames({class1: true, class2 : false});

// support for all type of data
getClassNames('class1', 'class2', null, undefined, 3, ['class3', 'class4'], { 
    class5 : function() { return false; },
    class6 : function() { return true; }
});

<div className={getClassNames('show', {class1: true, class2 : false})} /> // "show class1"

1

Com base no valor de this.props.showBulkActionsvocê pode alternar classes dinamicamente da seguinte maneira.

<div ...{...this.props.showBulkActions 
? { className: 'btn-group pull-right show' } 
: { className: 'btn-group pull-right hidden' }}>

1

Gostaria de acrescentar que você também pode usar um conteúdo variável como parte da classe

<img src={src} alt="Avatar" className={"img-" + messages[key].sender} />

O contexto é um bate-papo entre um bot e um usuário, e os estilos mudam dependendo do remetente, este é o resultado do navegador:

<img src="http://imageurl" alt="Avatar" class="img-bot">

1

Isso é útil quando você tem mais de uma classe a acrescentar. Você pode ingressar em todas as classes na matriz com um espaço.

const visibility = this.props.showBulkActions ? "show" : ""
<div className={["btn-group pull-right", visibility].join(' ')}>

1

Substituir:

<div className="btn-group pull-right {this.props.showBulkActions ? 'show' : 'hidden'}">`

com:

<div className={`btn-group pull-right ${this.props.showBulkActions ? 'show' : 'hidden'}`}


0

Achei isso que explica como fazê-lo com uma biblioteca ternária e com Classnames

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.