Como adiciono atributos condicionalmente aos componentes do React?

551

Existe uma maneira de adicionar atributos apenas a um componente React se uma determinada condição for atendida?

Eu devo adicionar os atributos obrigatório e readOnly para formar elementos com base em uma chamada Ajax após a renderização, mas não consigo ver como resolver isso, pois readOnly = "false" não é o mesmo que omitir o atributo completamente.

O exemplo abaixo deve explicar o que eu quero, mas não funcionará (Erro de análise: identificador inesperado).

var React = require('React');

var MyOwnInput = React.createClass({
    render: function () {
        return (
            <div>
                <input type="text" onChange={this.changeValue} value={this.getValue()} name={this.props.name}/>
            </div>
        );
    }
});

module.exports = React.createClass({
    getInitialState: function () {
        return {
            isRequired: false
        }
    },
    componentDidMount: function () {
        this.setState({
            isRequired: true
        });
    },
    render: function () {
        var isRequired = this.state.isRequired;

        return (
            <MyOwnInput name="test" {isRequired ? "required" : ""} />
        );
    }
});
Remi Sture
fonte
1
Pode ser que um comentário ajude alguém, descobri que o React 16.7 não é renderizado novamente e atualize os atributos html do componente se você os tiver alterado apenas em uma loja (fe redux) e vinculado ao componente. Isso significa que o componente possui fe aria-modal=true, você envia as alterações (para false) para o armazenamento de atributos aria / data , mas nada mais é alterado (como o conteúdo, a classe ou as variáveis ​​do componente), pois o ReactJs não atualiza a ária / dados atraem nesses componentes. Eu estive brincando o dia inteiro para perceber isso.
AlexNikonov 13/02/19

Respostas:

535

Aparentemente, para certos atributos, o React é inteligente o suficiente para omitir o atributo se o valor que você passar para ele não for verdadeiro. Por exemplo:

var InputComponent = React.createClass({
    render: function() {
        var required = true;
        var disabled = false;

        return (
            <input type="text" disabled={disabled} required={required} />
        );
    }
});

vai resultar em:

<input type="text" required>

Atualização: se alguém estiver curioso sobre como / por que isso acontece, você pode encontrar detalhes no código-fonte do ReactDOM, especificamente nas linhas 30 e 167 do arquivo DOMProperty.js .

juandemarco
fonte
45
Geralmente nullsignifica "agir como se eu não o tivesse especificado". Para booleano dom atributos verdadeiro / falso é preferido em relação repetindo o nome de atributo / falso, por exemplo, <input disabled>compila aReact.createElement('input', {disabled: true})
Brigand
Concordo. Repito o nome porque tive problemas no passado com certos navegadores e o hábito ficou tão grande comigo que adicionei manualmente a ="required"parte. O Chrome realmente processou apenas o atributo sem o valor.
21715 juandemarco
8
readonlynunca é adicionado porque o React está esperando o atributo readOnly(com O maiúsculo).
Max
8
Obrigado! Verifique se o valor não é apenas uma sequência vazia ou zero, pois eles podem não ser removidos. Por exemplo, você poderia passar um valor como este, e ele deve se certificar de que é removido se for avaliado como false: alt={props.alt || null}.
Jake
5
Obrigado, @Jake. Eu tentei definir o atributo como false, mas apenas nullverifiquei se o atributo foi realmente removido.
Nathan Arthur
387

resposta de juandemarco geralmente está correta, mas aqui está outra opção.

Crie um objeto como quiser:

var inputProps = {
  value: 'foo',
  onChange: this.handleChange
};

if (condition)
  inputProps.disabled = true;

Renderize com spread, opcionalmente passando outros adereços também.

<input
    value="this is overridden by inputProps"
    {...inputProps}
    onChange={overridesInputProps}
 />
Brigand
fonte
14
Isso é realmente muito útil, especialmente ao adicionar muitas propriedades condicionalmente (e eu pessoalmente não tinha idéia de que isso poderia ser feito dessa maneira).
21715 juandemarco
1
Muito elegante, mas não deveria ser inputProps.disabled = true?
Joppe
muito simples, tornei meu código mais legível sem ter várias condições.
Naveen Kumar PG
Se alguém se importa com a semântica precisa desse "açúcar", você pode olhar para o script no qual seu .jsx é transpilado e verá que uma função _extendsfoi adicionada a ele, que (em circunstâncias normais) terá como propsbase os "atributos normais" e aplique Object.assign(props, inputProps).
Nathan Chappell
299

Aqui está um exemplo do uso de Bootstrap 's Buttonvia Reagir-Bootstrap (versão 0.32.4):

var condition = true;

return (
  <Button {...(condition ? {bsStyle: 'success'} : {})} />
);

Dependendo da condição, um {bsStyle: 'success'}ou {}será devolvido. O operador de propagação espalhará as propriedades do objeto retornado para o Buttoncomponente. No caso de falsidade, como não existem propriedades no objeto retornado, nada será passado para o componente.


Uma maneira alternativa baseada no comentário de Andy Polhill :

var condition = true;

return (
  <Button bsStyle={condition ? 'success' : undefined} />
);

A única pequena diferença é que no segundo exemplo o componente interno <Button/>do propsobjecto terá uma chave bsStylecom um valor de undefined.

Arman Yeghiazaryan
fonte
5
@Punit, O operador spread tem uma precedência menor que o operador condicional; portanto, a condição é avaliada primeiro ( {bsStyle: 'success'}ou {}resulta dela) e, em seguida, o objeto é espalhado.
Victor Zamanian
5
Se o seguinte fizesse o mesmo <Button bsStyle={ condition ? 'success': undefined } /> , acho a sintaxe um pouco mais fácil, a passagem undefinedomitirá a propriedade.
Andy Polhill
3
O @AndyPolhill parece bom para mim e muito mais fácil de ler o código, a única pequena diferença é que, no exemplo de código <Button/>, o propsobjeto do componente interno terá uma chave bsStylecom o valor de undefined.
Arman Yeghiazaryan
@AndyPolhill a razão pela qual a sintaxe parece mais difícil de ler é porque faltam alguns parênteses implícitos, o que faz com que o exemplo pareça estranho e mais difícil de entender. Editando o exemplo para adicionar parênteses.
Govind Rai
1
O primeiro método funcionou perfeitamente para mim, obrigado
Liran H
86

Aqui está uma alternativa.

var condition = true;

var props = {
  value: 'foo',
  ...( condition && { disabled: true } )
};

var component = <div { ...props } />;

Ou sua versão embutida

var condition = true;

var component = (
  <div
    value="foo"
    { ...( condition && { disabled: true } ) } />
);
Estação
fonte
9
Eu gosto dessa abordagem, me deixa legal entre meus colegas de trabalho. Brincadeiras à parte, pelo que parece, os adereços são passados ​​como um par de valores-chave, afinal, está correto?
precisa saber é o seguinte
1
Se conditionfor falso, isso tentará expandir / iterar sobre falso, o que não acho correto.
Lars Nyström
1
@ LarsNyström, isso faz sentido. O operador de propagação aceita apenas iteráveis, onde falsenão é um. Basta verificar com Babel. Isso funciona quando se conditionavalia falso, desde a maneira como Babel implementa o operador. Embora possa ser uma solução trivial ...( condition ? { disabled: true } : {} ), ela se torna um pouco detalhada. Obrigado por esta boa entrada!
Temporada
+1 Essa abordagem é necessária se você deseja gerar resultados data-*ou aria-*atributos condicionalmente , como eles são um caso especial em JSX; portanto data-my-conditional-attr={ false }, produzirá em data-my-conditional-attr="false"vez de omitir o atributo. facebook.github.io/react/docs/dom-elements.html
ptim
32

Aqui está uma maneira de fazer isso.

Com uma condição :

<Label
    {...{
      text: label,
      type,
      ...(tooltip && { tooltip }),
      isRequired: required
    }}
/>

Eu ainda prefiro usar a maneira regular de transmitir adereços, porque é mais legível (na minha opinião) no caso de não ter condicionais.

Sem um condicional :

<Label text={label} type={type} tooltip={tooltip} isRequired={required} />
Tony Tai Nguyen
fonte
Você poderia explicar como essa parte funciona - ...(tooltip && { tooltip }),? Ele funciona no componente, mas quando tento usar algo assim no código, recebo um erro, o que significa que tento espalhar um valor não-iterável
skwisgaar 16/03
provavelmente porque falseyValue && {}retornará falso, então é provável que você esteja se espalhando por falso, por exemplo ...(false). muito melhor usar a expressão completa para que o spread continue a se comportar ...(condition ? {foo: 'bar'} : {})
lfender6445 20/04
19

Você pode usar o mesmo atalho, usado para adicionar / remover (partes de) componentes ( {isVisible && <SomeComponent />}).

class MyComponent extends React.Component {
  render() {
    return (
      <div someAttribute={someCondition && someValue} />
    );
  }
}
GijsjanB
fonte
3
Se someConditionfor verdadeiro, mas someValuefor falso (por exemplo false, ele próprio 0, etc.), o atributo ainda é incluído? Isso é importante se for necessário incluir explicitamente um valor falso, por exemplo, a 0para um atributo de coordenada etc.
Andrew Willems
Normalmente, o atributo é omitido, mas não no caso de data-*e aria-*, veja meu comentário acima. Se você citar o valor ou convertê-lo como uma String, o atributo será exibido: por exemplo, someAttr={ `${falsyValue}` }poderia renderizarsomeAttr="false"
ptim
19

Digamos que queremos adicionar uma propriedade customizada (usando aria- * ou data- *) se uma condição for verdadeira:

{...this.props.isTrue && {'aria-name' : 'something here'}}

Digamos que queremos adicionar uma propriedade de estilo se uma condição for verdadeira:

{...this.props.isTrue && {style : {color: 'red'}}}
Mina Luke
fonte
10

Se você usa o ECMAScript 6, pode simplesmente escrever assim.

// First, create a wrap object.
const wrap = {
    [variableName]: true
}
// Then, use it
<SomeComponent {...{wrap}} />
snyh
fonte
6

Isso deve funcionar, pois seu estado será alterado após a chamada do Ajax e o componente pai será renderizado novamente.

render : function () {
    var item;
    if (this.state.isRequired) {
        item = <MyOwnInput attribute={'whatever'} />
    } else {
        item = <MyOwnInput />
    }
    return (
        <div>
            {item}
        </div>
    );
}
Michael Parker
fonte
3

No React, você pode renderizar condicionalmente os componentes, mas também seus atributos, como props, className, id e muito mais.

No React, é uma prática muito boa usar o operador ternário que pode ajudá-lo a renderizar condicionalmente os Componentes.

Um exemplo também mostra como renderizar condicionalmente o Component e seu atributo de estilo.

Aqui está um exemplo simples:

class App extends React.Component {
  state = {
    isTrue: true
  };

  render() {
    return (
      <div>
        {this.state.isTrue ? (
          <button style={{ color: this.state.isTrue ? "red" : "blue" }}>
            I am rendered if TRUE
          </button>
        ) : (
          <button>I am rendered if FALSE</button>
        )}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Juraj
fonte
Isso pode ficar muito confuso com muitos atributos. Eu gosto mais da variante espalhada.
Remi Sture
Sim Você está certo, mas isso é para alguém que precisa ter uma visão geral, darei outro exemplo. Mas quer manter as coisas simples.
Juraj
0

Considerando a postagem JSX In Depth , você pode resolver seu problema desta maneira:

if (isRequired) {
  return (
    <MyOwnInput name="test" required='required' />
  );
}
return (
    <MyOwnInput name="test" />
);
Viktor Kireev
fonte