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?

apexdodge
fonte
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á.

spitfire109
fonte
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.

Diego V
fonte
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'}`}>
Bertrand
fonte
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} />
}
musa
fonte
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

escamoso
fonte
8

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

Pencilcheck
fonte
8

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

<div className={"btn-group pull-right " + (this.props.showBulkActions ? "show" : "")}>
Eugene Chybisov
fonte
1
Isso acrescentará falseclasse quando a condição falhar.
RA.
6

Você pode usar matrizes ES6 em vez de nomes de classe. A resposta é baseada no artigo do Dr. Axel Rauschmayer: Adicionando condicionalmente entradas dentro de matrizes e literais de objetos .

<div className={[
                 "classAlwaysPresent", 
                 ...Array.from(condition && ["classIfTrue"])
                ].join(" ")} />
Tudor Morar
fonte
por favor, expanda isso, qual é a condição?
Mibbit
condição const = (1 === 1);
Tudor Morar
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; 
}
pery mimon
fonte
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(' ')}/>
Nate Ben
fonte
3

você pode usar isso:

<div className={"btn-group pull-right" + (this.props.showBulkActions ? ' show' : ' hidden')}>
AmirBll
fonte
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>
    );
  }
});
Manoj Amalraj
fonte
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"
Tushar Sharma
fonte
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' }}>
Vladimir Trifonov
fonte
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">
JC
fonte
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(' ')}>
kooskoos
fonte
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'}`}
Amit Agarwal
fonte
0

Referência à resposta do @split fire, podemos atualizá-la com literais do modelo, que são mais legíveis. Para referência literal do modelo javascript do Google Checkout

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

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

chachan
fonte