Jak warunkowo dodać atrybuty do składników React?

549

Czy istnieje sposób dodawania atrybutów do komponentu React tylko wtedy, gdy spełniony jest określony warunek?

Powinienem dodać wymagane i atrybuty readOnly, aby utworzyć elementy oparte na wywołaniu Ajax po renderowaniu, ale nie widzę, jak to rozwiązać, ponieważ readOnly = „false” to nie to samo, co całkowite pominięcie atrybutu.

Poniższy przykład powinien wyjaśnić, czego chcę, ale to nie zadziała (Błąd analizy: nieoczekiwany identyfikator).

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
źródło
1
Może być jeden komentarz, który może komuś pomóc, okazało się, że React 16.7 nie rerenderuje i aktualizuje atrybuty HTML komponentu, jeśli zmieniłeś tylko je w sklepie (np. Redux) i powiązałeś z komponentem. Oznacza to, że komponent ma fe aria-modal=true, przesuwasz zmiany (do wartości false) do magazynu atrybutów aria / data , ale nic innego się nie zmienia (takie jak zawartość komponentu lub klasa lub zmienne w nim zawarte), w wyniku czego ReactJs nie zaktualizuje aria / atrasy danych w tych komponentach. Bałam się przez cały dzień, żeby to zrozumieć.
AlexNikonov

Odpowiedzi:

534

Najwyraźniej w przypadku niektórych atrybutów React jest wystarczająco inteligentny, aby pominąć atrybut, jeśli przekazywana mu wartość nie jest prawdziwa. Na przykład:

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

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

spowoduje:

<input type="text" required>

Aktualizacja: jeśli ktoś jest ciekaw, jak / dlaczego tak się dzieje, można znaleźć szczegóły w kodzie źródłowym ReactDOM, w szczególności na liniach 30 i 167 w DOMProperty.js pliku.

juandemarco
źródło
45
Ogólnie nulloznacza „zachowuj się, jakbym wcale tego nie określił”. W przypadku atrybutów typu boolean preferowane jest ustawienie prawda / fałsz zamiast powtarzania nazwy atrybutu / fałsz, np. <input disabled>Kompilacja doReact.createElement('input', {disabled: true})
Brigand
Zgadzam się. Powtarzam nazwę, ponieważ w przeszłości miałem problemy z niektórymi przeglądarkami, a nawyk utkwił we mnie tak bardzo, że ręcznie dodałem ="required"część. Chrome faktycznie zrenderował tylko atrybut bez wartości.
juandemarco
8
readonlynigdy się nie dodaje, ponieważ React oczekuje atrybutu readOnly(z dużym O).
Max
8
Dzięki! Upewnij się, że wartość nie jest pustym ciągiem zerowym, ponieważ mogą one nie zostać usunięte. Na przykład, można przekazać wartość takiego, i powinien upewnić się, że zostanie usunięty, jeśli FALSE: alt={props.alt || null}.
Jake
5
Dzięki, @Jake. Próbowałem ustawić atrybut na false, ale nullupewniłem się, że atrybut został faktycznie usunięty.
Nathan Arthur
386

Odpowiedź juandemarco jest zwykle poprawna, ale oto inna opcja.

Zbuduj obiekt tak, jak lubisz:

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

if (condition)
  inputProps.disabled = true;

Renderuj z rozkładaniem, opcjonalnie również z innymi rekwizytami.

<input
    value="this is overridden by inputProps"
    {...inputProps}
    onChange={overridesInputProps}
 />
Bandyta
źródło
14
Jest to faktycznie bardzo przydatne, szczególnie przy warunkowym dodawaniu wielu właściwości (a ja osobiście nie miałem pojęcia, że ​​można to zrobić w ten sposób).
juandemarco
1
Bardzo elegancki, ale czy nie powinien to być inputProps.disabled = true?
Joppe,
bardzo proste, sprawiłem, że mój kod jest bardziej czytelny bez wielu warunków.
Naveen Kumar PG
Jeśli ktoś dba o dokładną semantykę tego „cukru”, możesz spojrzeć na skrypt, w który przeniesiony jest twój .jsx, zobaczysz, że _extendsdodano do niego funkcję , która (w normalnych okolicznościach) pobierze propsskonstruowaną z „normalne atrybuty” i zastosowanie Object.assign(props, inputProps).
Nathan Chappell
299

Poniżej przedstawiono przykład zastosowania bootstrap „S Buttonpoprzez React-Bootstrap (wersja 0.32.4)

var condition = true;

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

W zależności od warunku albo {bsStyle: 'success'}albo {}zostanie zwrócone. Operator rozkładania rozłoży następnie właściwości zwróconego obiektu na Buttonkomponent. W przypadku fałszowania, ponieważ na zwróconym obiekcie nie istnieją żadne właściwości, nic nie zostanie przekazane do komponentu.


Alternatywny sposób oparty na komentarzu Andy'ego Polhilla :

var condition = true;

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

Jedyną niewielką różnicą, że w drugim przykładzie Element wewnętrzny <Button/>jest propsobiekt zawiera klucz bsStyleo wartości undefined.

Arman Yeghiazaryan
źródło
5
@Punit Operator rozpiętość ma niższy priorytet niż operator warunkowego, a więc jest warunek pierwsza (albo {bsStyle: 'success'}czy {}wyniki z niego), to przedmiot jest rozproszonym.
Victor Zamanian
5
Gdyby poniższe zrobiły to samo, <Button bsStyle={ condition ? 'success': undefined } /> uważam, że składnia jest nieco łatwiejsza, przekazywanie undefinedpomija właściwość.
Andy Polhill,
3
@AndyPolhill wygląda dla mnie dobry i dużo łatwiej odczytać kodu, jedyną różnicą jest to, że mały w przykładzie kodu wewnętrzny komponent <Button/>„s propsobiekt będzie mieć klucz bsStylez wartości undefined.
Arman Yeghiazaryan
@AndyPolhill przyczyną, dla której składnia wydaje się trudniejsza do odczytania, jest brak niektórych ukrytych nawiasów, przez co przykład wygląda na obcy i trudniejszy do zrozumienia. Edycja przykładu w celu dodania nawiasów.
Govind Rai
1
Pierwsza metoda działała dla mnie idealnie, dziękuję
Liran H.
86

Oto alternatywa.

var condition = true;

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

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

Lub jego wersja wbudowana

var condition = true;

var component = (
  <div
    value="foo"
    { ...( condition && { disabled: true } ) } />
);
Pora roku
źródło
9
Podoba mi się to podejście, które sprawia, że ​​czuję się fajnie wśród moich kolegów z pracy. Żartując, z wyglądu, rekwizyty są po prostu przekazywane jako para klucz-wartość, czy to prawda?
JohnnyQ,
1
Jeśli conditionjest fałszem, to spróbuje rozwinąć / iterować ponad fałszem, co nie uważam za poprawne.
Lars Nyström
1
@ LarsNyström, To ma sens. Operator spreadu akceptuje tylko iterowalne, gdzie falsenie ma jednego. Po prostu skontaktuj się z Babel. Działa to przy conditionocenie wartości false, ponieważ sposób, w jaki Babel implementuje operatora. Choć może to być trywialne obejście ...( condition ? { disabled: true } : {} ), staje się wtedy nieco gadatliwe. Dzięki za ten miły wkład!
Sezon
+1 To podejście jest wymagane, jeśli chcesz warunkowo generować dane wyjściowe data-*lub aria-*atrybuty, ponieważ są one specjalnym przypadkiem w JSX, więc data-my-conditional-attr={ false }będą generować dane wyjściowe data-my-conditional-attr="false"zamiast pomijać atrybut. facebook.github.io/react/docs/dom-elements.html
ptim
32

Oto jak to zrobić.

Z warunkiem :

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

Nadal wolę używać zwykłego sposobu przekazywania rekwizytów, ponieważ jest on bardziej czytelny (moim zdaniem) w przypadku braku warunkowych.

Bez warunku :

<Label text={label} type={type} tooltip={tooltip} isRequired={required} />
Tony Tai Nguyen
źródło
Czy możesz wyjaśnić, jak działa ta część - ...(tooltip && { tooltip }),? Działa na komponencie, ale kiedy próbuję użyć czegoś takiego w kodzie,
pojawia
prawdopodobnie dlatego, falseyValue && {}że zwróci false, więc prawdopodobnie rozprzestrzeniasz się na false, np...(false) . o wiele lepiej jest użyć pełnego wyrażenia, aby spread zachowywał się dalej ...(condition ? {foo: 'bar'} : {})
lfender6445
19

Możesz użyć tego samego skrótu, który służy do dodawania / usuwania (części) komponentów ( {isVisible && <SomeComponent />}).

class MyComponent extends React.Component {
  render() {
    return (
      <div someAttribute={someCondition && someValue} />
    );
  }
}
GijsjanB
źródło
3
Jeśli someConditionjest to prawda, ale someValuejest to fałsz (np. falseSam 0, itp.), Czy atrybut nadal jest uwzględniany? Jest to ważne, jeśli konieczne jest jawne dołączenie wartości fałszowania, np. 0Dla atrybutu współrzędnych itp.
Andrew Willems,
Zwykle atrybut jest pomijany, ale nie w przypadku data-*i aria-*, patrz mój komentarz powyżej. Jeśli podasz wartość lub rzucisz ją jako ciąg, atrybut wyświetli: np. someAttr={ `${falsyValue}` }Może renderowaćsomeAttr="false"
ptim
19

Powiedzmy, że chcemy dodać niestandardową właściwość (używając aria- * lub data- *), jeśli warunek jest spełniony:

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

Powiedzmy, że chcemy dodać właściwość stylu, jeśli warunek jest spełniony:

{...this.props.isTrue && {style : {color: 'red'}}}
Mina Luke
źródło
10

Jeśli używasz ECMAScript 6, możesz po prostu pisać w ten sposób.

// First, create a wrap object.
const wrap = {
    [variableName]: true
}
// Then, use it
<SomeComponent {...{wrap}} />
snyh
źródło
7

Powinno to działać, ponieważ stan zmieni się po wywołaniu Ajax, a komponent nadrzędny zostanie zrenderowany.

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

W React możesz warunkowo renderować komponenty, ale także ich atrybuty, takie jak rekwizyty, nazwa_klasy, identyfikator i inne.

W React bardzo dobrą praktyką jest używanie operatora trójskładnikowego, który może pomóc w warunkowym renderowaniu Komponentów.

Przykład pokazuje również, jak warunkowo renderować komponent i jego atrybut stylu.

Oto prosty przykład:

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
źródło
Może to być bardzo nieporządne z wieloma atrybutami. Wariant rozprzestrzeniania bardziej mi się podoba.
Remi Sture,
Tak Masz rację, ale dla kogoś, kto musi uzyskać przegląd, dam inny przykład. Ale chcę zachować prostotę.
Juraj,
0

Biorąc pod uwagę post JSX In Depth , możesz rozwiązać swój problem w ten sposób:

if (isRequired) {
  return (
    <MyOwnInput name="test" required='required' />
  );
}
return (
    <MyOwnInput name="test" />
);
Viktor Kireev
źródło