Come posso aggiungere condizionalmente attributi ai componenti di React?


551

C'è un modo per aggiungere attributi a un componente React solo se viene soddisfatta una determinata condizione?

Dovrei aggiungere gli attributi obbligatori e readOnly per formare elementi basati su una chiamata Ajax dopo il rendering, ma non riesco a vedere come risolverlo poiché readOnly = "false" non equivale a omettere completamente l'attributo.

L'esempio seguente dovrebbe spiegare quello che voglio, ma non funzionerà (errore di analisi: identificatore imprevisto).

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" : ""} />
        );
    }
});

1
Può essere un commento aiutare qualcuno, ho scoperto che React 16.7 non esegue nuovamente il rendering e aggiorna gli attributi html del componente se li hai cambiati solo in un negozio (fe redux) e collegati al componente. Questo significa che il componente ha fe aria-modal=true, spingi le modifiche (su false) nel negozio di attributi aria / data , ma non viene cambiato nient'altro (come il contenuto del componente o la classe o le variabili) poiché il risultato ReactJs non aggiornerà aria / i dati attirano quei componenti. Ho fatto casino per tutto il giorno per rendermene conto.
AlexNikonov,

Risposte:


535

Apparentemente, per certi attributi, React è abbastanza intelligente da omettere l'attributo se il valore che gli passi non è vero. Per esempio:

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

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

comporterà:

<input type="text" required>

Aggiornamento: se qualcuno è curioso di sapere come / perché ciò accade, è possibile trovare i dettagli nel codice sorgente di ReactDOM, in particolare alle righe 30 e 167 del file DOMProperty.js .


45
Generalmente nullsignifica "comportati come se non l'avessi specificato affatto". Per gli attributi dom booleani è preferibile true / false piuttosto che ripetere il nome dell'attributo / false, ad es. <input disabled>Compila inReact.createElement('input', {disabled: true})
Brigand

Sono d'accordo. Ripeto il nome perché in passato ho avuto problemi con alcuni browser e l'abitudine è rimasta così forte che ho aggiunto manualmente la ="required"parte. Chrome ha effettivamente reso solo l'attributo senza il valore.
juandemarco,

8
readonlynon viene mai aggiunto perché React si aspetta l'attributo readOnly(con una O maiuscola).
Max

8
Grazie! Assicurati che il valore non sia solo una stringa vuota o zero, questi potrebbero non essere rimossi. Ad esempio, è possibile passare un valore come questo, e dovrebbe assicurarsi che sia rimossa se vale false: alt={props.alt || null}.
Jake,

5
Grazie, @Jake. Avevo provato a impostare l'attributo su false, ma solo nullassicurato che l'attributo fosse effettivamente rimosso.
Nathan Arthur,

387

La risposta di juandemarco è generalmente corretta, ma ecco un'altra opzione.

Costruisci un oggetto come preferisci:

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

if (condition)
  inputProps.disabled = true;

Render con diffusione, opzionalmente passando anche altri oggetti di scena.

<input
    value="this is overridden by inputProps"
    {...inputProps}
    onChange={overridesInputProps}
 />

14
Questo in realtà è molto utile, specialmente quando si aggiungono molte proprietà in modo condizionale (e personalmente non avevo idea che potesse essere fatto in questo modo).
juandemarco,

1
Molto elegante, ma non dovrebbe essere inputProps.disabled = true?
Joppe,

molto semplice, ho reso il mio codice più leggibile senza avere più condizioni.
Naveen Kumar PG

Se qualcuno si preoccupa della semantica precisa di questo "zucchero", puoi guardare lo script in cui è traspilato il tuo .jsx vedrai che _extendsè stata aggiunta una funzione ad esso, che (in circostanze normali) prenderà il propscostruito da gli "attributi normali" e si applicano Object.assign(props, inputProps).
Nathan Chappell,

299

Ecco un esempio di utilizzo di Bootstrap 's Buttonvia React-Bootstrap (versione 0.32.4):

var condition = true;

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

A seconda delle condizioni, sia {bsStyle: 'success'}o {}sarà restituito. L'operatore di diffusione distribuirà quindi le proprietà dell'oggetto restituito al Buttoncomponente. Nel caso errato, poiché non esiste alcuna proprietà sull'oggetto restituito, nulla verrà passato al componente.


Un modo alternativo basato sul commento di Andy Polhill :

var condition = true;

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

L'unica differenza è che piccolo nel secondo esempio il componente interno <Button/>'s propsoggetto avrà una chiave bsStylecon un valore undefined.


5
@Punit, L'operatore spread ha una precedenza inferiore rispetto all'operatore condizionale, quindi la condizione viene valutata prima ( {bsStyle: 'success'}o uno dei {}risultati), quindi l'oggetto viene diffuso.
Victor Zamanian,

5
Se ciò che segue fa lo stesso <Button bsStyle={ condition ? 'success': undefined } /> trovo la sintassi leggermente più semplice, passando undefinedometterò la proprietà.
Andy Polhill,

3
@AndyPolhill sembra buono per me e molto più facile da leggere il codice, l'unica differenza è che piccolo nel tuo esempio di codice componente interna <Button/>'s propsoggetto avrà una chiave bsStylecon valore undefined.
Arman Yeghiazaryan,

@AndyPolhill il motivo per cui la sintassi sembra più difficile da leggere è perché manca alcune parentesi implicite che rendono l'esempio estraneo e più difficile da capire. Modifica dell'esempio per aggiungere parentesi.
Govind Rai,

1
Il primo metodo ha funzionato perfettamente per me, grazie
Liran H

86

Ecco un'alternativa.

var condition = true;

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

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

O la sua versione in linea

var condition = true;

var component = (
  <div
    value="foo"
    { ...( condition && { disabled: true } ) } />
);

9
Mi piace questo approccio, mi rende cool tra i miei compagni di lavoro. Scherzi a parte, a quanto pare, gli oggetti di scena vengono semplicemente passati come coppia chiave-valore, dopo tutto, è corretto?
JohnnyQ

1
Se conditionè falso, questo tenterà di espandere / iterare su falso, che non credo sia corretto.
Lars Nyström

1
@ LarsNyström, ha senso. L'operatore spread accetta solo iterabili, dove falsenon lo è. Basta controllare con Babele. Funziona con esso quando viene conditionvalutato falso dal modo in cui Babel implementa l'operatore. Sebbene possa essere una banale soluzione alternativa ...( condition ? { disabled: true } : {} ), allora diventa un po 'prolissa. Grazie per questo bel contributo!
Stagione

+1 Questo approccio è necessario se si desidera eseguire l'output condizionato data-*o gli aria-*attributi, poiché sono un caso speciale in JSX, quindi data-my-conditional-attr={ false }verrà generato data-my-conditional-attr="false"anziché omettere l'attributo. facebook.github.io/react/docs/dom-elements.html
ptim

32

Ecco un modo per farlo.

Con un condizionale :

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

Preferisco ancora usare il modo regolare di far passare gli oggetti di scena, perché è più leggibile (secondo me) nel caso in cui non ci siano condizionali.

Senza condizioni :

<Label text={label} type={type} tooltip={tooltip} isRequired={required} />

Potresti spiegare come funziona questa parte - ...(tooltip && { tooltip }),? Funziona sul componente ma quando provo a usare qualcosa di simile nel codice ricevo un errore che significa che provo a diffondere un valore non iterabile
skwisgaar

probabilmente perché falseyValue && {}restituirà false, quindi è probabile che ti stia diffondendo su false ad es ...(false). molto meglio usare la piena espressione in modo che lo spread continui a comportarsi ...(condition ? {foo: 'bar'} : {})
lfender6445

19

È possibile utilizzare lo stesso collegamento utilizzato per aggiungere / rimuovere (parti di) componenti ( {isVisible && <SomeComponent />}).

class MyComponent extends React.Component {
  render() {
    return (
      <div someAttribute={someCondition && someValue} />
    );
  }
}

3
Se someConditionè vero ma someValueè falso (ad es. Se falsestesso, o 0, ecc.), L'attributo viene ancora incluso? Ciò è importante se è necessario includere esplicitamente un valore errato, ad es. A 0per un attributo di coordinate, ecc.
Andrew Willems,

Normalmente, l'attributo viene omesso, ma non nel caso di data-*e aria-*, vedere il mio commento sopra. Se si cita il valore o lo si lancia come stringa, verrà visualizzato l'attributo: ad esempio, someAttr={ `${falsyValue}` }potrebbe essere visualizzatosomeAttr="false"
ptim

19

Diciamo che vogliamo aggiungere una proprietà personalizzata (usando aria- * o data- *) se una condizione è vera:

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

Diciamo che vogliamo aggiungere una proprietà di stile se una condizione è vera:

{...this.props.isTrue && {style : {color: 'red'}}}

10

Se usi ECMAScript 6, puoi semplicemente scrivere così.

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

6

Questo dovrebbe funzionare, poiché il tuo stato cambierà dopo la chiamata Ajax e il componente padre verrà nuovamente visualizzato.

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

3

In React puoi rendere condizionalmente i componenti, ma anche i loro attributi, come oggetti di scena, className, id e altro.

In React è un'ottima pratica usare l' operatore ternario che può aiutarti a rendere condizionatamente i componenti.

Un esempio mostra anche come eseguire il rendering condizionale del componente e del suo attributo di stile.

Qui c'è un semplice esempio:

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>


Questo può diventare davvero disordinato con molti attributi. Mi piace di più la variante di diffusione.
Remi Sture,

Sì, hai ragione, ma questo è per qualcuno che ha bisogno di avere una visione d'insieme farò un altro esempio. Ma vuoi mantenere le cose semplici.
Juraj,

0

Considerando il post JSX In Depth , puoi risolvere il tuo problema in questo modo:

if (isRequired) {
  return (
    <MyOwnInput name="test" required='required' />
  );
}
return (
    <MyOwnInput name="test" />
);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.