Wie füge ich React-Komponenten bedingt Attribute hinzu?

551

Gibt es eine Möglichkeit, einer React-Komponente nur Attribute hinzuzufügen, wenn eine bestimmte Bedingung erfüllt ist?

Ich sollte erforderliche und readOnly-Attribute hinzufügen, um Elemente zu bilden, die auf einem Ajax-Aufruf nach dem Rendern basieren, aber ich kann nicht sehen, wie dies gelöst werden kann, da readOnly = "false" nicht dasselbe ist wie das vollständige Weglassen des Attributs.

Das folgende Beispiel sollte erklären, was ich will, aber es wird nicht funktionieren (Analysefehler: Unerwarteter Bezeichner).

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
quelle
1
Vielleicht hilft ein Kommentar jemandem, ich habe herausgefunden, dass React 16.7 die HTML-Attribute der Komponente nicht erneut rendert und aktualisiert, wenn Sie nur sie in einem Geschäft geändert haben (z. B. Redux) und an die Komponente gebunden sind. Dies bedeutet, dass die Komponente zB aria-modal=truehat. Sie verschieben die Änderungen (auf false) in den Speicher der Arien- / Datenattribute, aber nichts anderes wird geändert (wie der Inhalt oder die Klasse oder die Variablen der Komponente darin), da ReactJs aria / nicht aktualisiert . Daten attrs dass Komponenten. Ich habe den ganzen Tag herumgespielt, um das zu realisieren.
AlexNikonov

Antworten:

535

Anscheinend ist React für bestimmte Attribute intelligent genug, um das Attribut wegzulassen, wenn der Wert, den Sie an ihn übergeben, nicht wahr ist. Zum Beispiel:

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

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

wird darin enden, dass:

<input type="text" required>

Update: Wenn jemand neugierig ist, wie / warum dies geschieht, finden Sie Details im ReactDOM-Quellcode, insbesondere in den Zeilen 30 und 167 der Datei DOMProperty.js .

Juandemarco
quelle
45
Im Allgemeinen nullbedeutet "so tun, als hätte ich es überhaupt nicht angegeben". Für boolesche dom-Attribute wird true / false der Wiederholung des Attributnamens / false vorgezogen, z. B. <input disabled>Kompilierung anReact.createElement('input', {disabled: true})
Brigand
Genau. Ich wiederhole den Namen, weil ich in der Vergangenheit Probleme mit bestimmten Browsern hatte und die Gewohnheit so sehr bei mir blieb, dass ich den ="required"Teil manuell hinzufügte . Chrome hat tatsächlich nur das Attribut ohne den Wert gerendert.
Juandemarco
8
readonlywird nie hinzugefügt, da React das Attribut erwartet readOnly(mit einem Großbuchstaben O).
Max
8
Vielen Dank! Stellen Sie sicher, dass der Wert nicht nur eine leere Zeichenfolge oder Null ist. Diese werden möglicherweise nicht entfernt. Sie könnten beispielsweise einen Wert wie diesen übergeben und sicherstellen, dass er entfernt wird, wenn er als false ausgewertet wird : alt={props.alt || null}.
Jake
5
Danke, @Jake. Ich hatte versucht, das Attribut auf zu setzen false, aber nur nullsichergestellt, dass das Attribut tatsächlich entfernt wurde.
Nathan Arthur
386

Die Antwort von juandemarco ist normalerweise richtig, aber hier ist eine andere Option.

Erstellen Sie ein Objekt, wie Sie möchten:

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

if (condition)
  inputProps.disabled = true;

Mit Spread rendern, optional auch andere Requisiten weitergeben.

<input
    value="this is overridden by inputProps"
    {...inputProps}
    onChange={overridesInputProps}
 />
Räuber
quelle
14
Dies ist tatsächlich sehr nützlich, insbesondere wenn viele Eigenschaften bedingt hinzugefügt werden (und ich persönlich hatte keine Ahnung, dass dies auf diese Weise möglich ist).
Juandemarco
1
Sehr elegant, aber sollte es nicht inputProps.disabled = true sein?
Joppe
Sehr einfach, ich habe meinen Code lesbarer gemacht, ohne mehrere Bedingungen zu haben.
Naveen Kumar PG
Wenn sich jemand um die genaue Semantik dieses "Zuckers" kümmert, können Sie sich das Skript ansehen, in das Ihre .jsx-Datei transpiliert ist. Sie werden feststellen, dass eine Funktion _extendshinzugefügt wurde, die (unter normalen Umständen) die propskonstruierte Funktion übernimmt die "normalen Attribute" und gelten Object.assign(props, inputProps).
Nathan Chappell
299

Hier ist ein Beispiel der Verwendung von Bootstrap ‚s Buttonüber React-Bootstrap (Version 0.32.4):

var condition = true;

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

Je nach Zustand wird entweder {bsStyle: 'success'}oder {}zurückgegeben. Der Spread-Operator verteilt dann die Eigenschaften des zurückgegebenen Objekts auf die ButtonKomponente. Im falschen Fall wird nichts an die Komponente übergeben, da für das zurückgegebene Objekt keine Eigenschaften vorhanden sind.


Ein alternativer Weg basierend auf Andy Polhills Kommentar :

var condition = true;

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

Der einzige kleine Unterschied ist , dass bei dem zweiten Beispiel der innere Komponente <Button/>ist propsAufgabe , einen Schlüssel wird bsStylemit einem Wert von undefined.

Arman Yeghiazaryan
quelle
5
@Punit, Der Spread-Operator hat eine niedrigere Priorität als der bedingte Operator. Daher wird die Bedingung zuerst ausgewertet (entweder {bsStyle: 'success'}oder {}resultiert daraus), und dann wird das Objekt verteilt.
Victor Zamanian
5
Würde das Folgende das Gleiche tun, <Button bsStyle={ condition ? 'success': undefined } /> finde ich die Syntax etwas einfacher, wird beim Übergeben undefineddie Eigenschaft weggelassen.
Andy Polhill
3
@AndyPolhill sieht für mich gut und viel einfacher , den Code zu lesen, der einzige kleine Unterschied ist , dass in Ihrem Codebeispiel innere Komponente <Button/>‚s propsObjekt einen Schlüssel wird bsStylemit dem Wert undefined.
Arman Yeghiazaryan
@AndyPolhill Der Grund, warum die Syntax schwieriger zu lesen scheint, ist, dass einige implizite Klammern fehlen, wodurch das Beispiel fremd und schwerer zu verstehen ist. Bearbeiten des Beispiels zum Hinzufügen von Klammern.
Govind Rai
1
Die erste Methode hat perfekt für mich funktioniert, danke
Liran H
86

Hier ist eine Alternative.

var condition = true;

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

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

Oder seine Inline-Version

var condition = true;

var component = (
  <div
    value="foo"
    { ...( condition && { disabled: true } ) } />
);
Jahreszeit
quelle
9
Ich mag diesen Ansatz, er macht mich unter meinen Arbeitskollegen cool. Scherz beiseite, so wie es aussieht, werden die Requisiten doch nur als Schlüssel-Wert-Paar übergeben, ist das richtig?
JohnnyQ
1
Wenn dies conditionfalsch ist, wird versucht, über falsch zu expandieren / zu iterieren, was ich nicht für richtig halte.
Lars Nyström
1
@ LarsNyström, das macht Sinn. Der Spread-Operator akzeptiert nur iterables, wo falsees keine gibt. Fragen Sie einfach bei Babel nach. Dies funktioniert, wenn es als conditionfalsch ausgewertet wird, da Babel den Operator implementiert. Obwohl eine triviale Problemumgehung sein könnte, ...( condition ? { disabled: true } : {} )wird sie dann etwas ausführlich. Danke für diesen netten Input!
Saison
+1 Dieser Ansatz ist erforderlich, wenn Sie data-*oder aria-*Attribute bedingt ausgeben möchten , da dies in JSX ein Sonderfall ist. Das Attribut data-my-conditional-attr={ false }wird also ausgegeben, data-my-conditional-attr="false"anstatt es wegzulassen. facebook.github.io/react/docs/dom-elements.html
ptim
32

Hier ist eine Möglichkeit, wie ich es mache.

Mit einer Bedingung :

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

Ich bevorzuge es immer noch, Requisiten regelmäßig weiterzugeben, da sie (meiner Meinung nach) besser lesbar sind, wenn keine Bedingungen vorliegen.

Ohne Bedingung :

<Label text={label} type={type} tooltip={tooltip} isRequired={required} />
Tony Tai Nguyen
quelle
Könnten Sie bitte erklären, wie dieser Teil funktioniert - ...(tooltip && { tooltip }),? Es funktioniert zwar für Komponenten, aber wenn ich versuche, so etwas im Code zu verwenden, wird eine Fehlermeldung
angezeigt, die besagt,
wahrscheinlich, weil falseyValue && {}false zurückgegeben wird, so dass es wahrscheinlich ist, dass Sie sich auf false verbreiten, z ...(false). Es ist viel besser, den vollständigen Ausdruck zu verwenden, damit sich der Spread weiterhin verhält ...(condition ? {foo: 'bar'} : {})
lfender6445
19

Sie können dieselbe Verknüpfung verwenden, mit der (Teile von) Komponenten ( {isVisible && <SomeComponent />}) hinzugefügt / entfernt werden .

class MyComponent extends React.Component {
  render() {
    return (
      <div someAttribute={someCondition && someValue} />
    );
  }
}
GijsjanB
quelle
3
Wenn dies someConditionzutrifft, aber someValuefalsch ist (z. B. falseselbst oder 0usw.), wird das Attribut dann immer noch aufgenommen? Dies ist wichtig, wenn es notwendig ist, einen falschen Wert explizit anzugeben, z. B. ein 0für ein Koordinatenattribut usw.
Andrew Willems
Normalerweise wird das Attribut weggelassen, aber nicht im Fall von data-*und aria-*, siehe meinen Kommentar oben. Wenn Sie den Wert zitieren oder als String someAttr={ `${falsyValue}` }someAttr="false"
umwandeln
19

Angenommen, wir möchten eine benutzerdefinierte Eigenschaft hinzufügen (mit aria- * oder data- *), wenn eine Bedingung erfüllt ist:

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

Angenommen, wir möchten eine Stileigenschaft hinzufügen, wenn eine Bedingung erfüllt ist:

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

Wenn Sie ECMAScript 6 verwenden, können Sie einfach so schreiben.

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

Dies sollte funktionieren, da sich Ihr Status nach dem Ajax-Aufruf ändert und die übergeordnete Komponente erneut gerendert wird.

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

In React können Sie Komponenten, aber auch deren Attribute wie Requisiten, Klassenname, ID und mehr bedingt rendern.

In React ist es sehr empfehlenswert, den ternären Operator zu verwenden Sie Komponenten bedingt rendern können.

Ein Beispiel zeigt auch, wie Komponenten und ihr Stilattribut bedingt gerendert werden.

Hier ist ein einfaches Beispiel:

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
quelle
Dies kann mit vielen Attributen sehr chaotisch werden. Ich mag die Spread-Variante besser.
Remi Sture
Ja, Sie haben Recht, aber dies ist für jemanden, der sich einen Überblick verschaffen muss. Ich werde ein weiteres Beispiel geben. Aber ich möchte die Dinge einfach halten.
Juraj
0

In Anbetracht des Post JSX In Depth können Sie Ihr Problem folgendermaßen lösen:

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