Як я умовно додаю атрибути до компонентів React?


550

Чи є спосіб додати атрибути до компонента React лише тоді, коли виконано певну умову?

Я повинен додати необхідні та readOnly атрибути для формування елементів, заснованих на виклику Ajax після візуалізації, але я не можу зрозуміти, як це вирішити, оскільки readOnly = "false" - це не те, що повністю опускати атрибут.

У наведеному нижче прикладі слід пояснити, що я хочу, але це не буде працювати (помилка розбору: несподіваний ідентифікатор).

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
Можливо, один коментар допоможе комусь, я дізнався, що React 16.7 не ретранслюється та оновлює HTML-атрибути компонента, якщо ви змінили їх лише у магазині (fe redux) та прив'язали до компонента. Це означає, що компонент має fe aria-modal=true, ви натискаєте зміни (на хибність) до сховища атрибутів aria / data , але нічого іншого не змінюється (наприклад, вміст компонента чи клас чи змінні там), оскільки результат ReactJs не оновить aria / дані в цих компонентах. Я цілий день возився, щоб зрозуміти це.
AlexNikonov

Відповіді:


534

Мабуть, для певних атрибутів React досить розумний, щоб опустити атрибут, якщо значення, яке ви передаєте йому, не є правдою. Наприклад:

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

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

це призведе до:

<input type="text" required>

Оновлення: якщо кому - то цікаво, як / чому це відбувається, ви можете знайти докладну інформацію в вихідному коді ReactDOM, в зокрема , в рядках 30 і 167 з DOMProperty.js файлу.


45
Взагалі nullозначає "діяти так, як я його зовсім не вказував". Для булевих атрибутів dom відзначається true / false, ніж повторення атрибута / false, наприклад <input disabled>компіляція доReact.createElement('input', {disabled: true})
Brigand

Я згоден. Я повторюю назву, тому що в минулому у мене були проблеми з певними браузерами, і звичка настільки приклеїлася до мене, що я додав ="required"деталь вручну . Chrome насправді надав лише атрибут без значення.
juandemarco

8
readonlyніколи не додається, оскільки React очікує атрибуту readOnly(з великим літером O).
Макс

8
Дякую! Переконайтеся, що значення не є просто порожнім рядком або нулем, вони можуть не бути видалені. Наприклад, ви могли б передати значення , як це, і він повинен переконатися , що він буде видалений , якщо він має значення FALSE: alt={props.alt || null}.
Джейк

5
Дякую, @Jake Я намагався встановити атрибут false, але лише nullпереконався, що атрибут фактично видалений.
Натан Артур

386

Відповідь juandemarco зазвичай правильна, але ось інший варіант.

Побудуйте об’єкт, як вам подобається:

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

if (condition)
  inputProps.disabled = true;

Візуалізуйте з розворотом, необов'язково передаючи й інші реквізити.

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

14
Це насправді дуже корисно, особливо якщо додавати багато властивостей умовно (і я особисто не мав уявлення, що це можна зробити так).
juandemarco

1
Дуже елегантно, але чи не повинно це бути inputProps.disabled = true?
Джоппе

дуже просто, я зробив свій код читабельнішим, маючи кілька умов.
Naveen Kumar PG

Якщо когось хвилює точна семантика цього "цукру", ви можете подивитися на скрипт, що ваш .jsx перетворений у вас, ви побачите, що до _extendsнього додана функція , яка (за звичайних обставин) візьме propsпобудовану з "нормальні атрибути" та застосовуються Object.assign(props, inputProps).
Натан Чаппелл

299

Ось приклад використання Bootstrap 's Buttonчерез React-Bootstrap (версія 0.32.4):

var condition = true;

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

Залежно від умови повернення {bsStyle: 'success'}або {}повернеться. Потім оператор розповсюдження буде поширювати властивості повернутого об'єкта на Buttonкомпонент. У хибному випадку, оскільки на поверненому об'єкті немає властивостей, компонент нічого не передасть.


Альтернативний спосіб, заснований на коментарі Енді Полхілла :

var condition = true;

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

Лише невелика різниця в тому , що в другому прикладі внутрішній компонент <Button/>«s propsоб'єкт буде мати ключ bsStyleзі значенням undefined.


5
@Punit, Оператор розповсюдження має нижчий пріоритет, ніж умовний оператор, тому умова оцінюється спочатку ( {bsStyle: 'success'}або є {}результатом від нього), потім цей об’єкт поширюється.
Віктор Замонян

5
Як би наступне зробило те саме, <Button bsStyle={ condition ? 'success': undefined } /> я вважаю синтаксис трохи простішим, передача undefinedбуде пропускати властивість.
Енді Полхілл

3
@AndyPolhill виглядає добре для мене і набагато легше читати код, тільки невелика різниця в тому , що в вашому прикладі коди внутрішнього компонента <Button/>«s propsоб'єкт буде мати ключ bsStyleзі значенням undefined.
Арман Єгіазарян

@AndyPolhill, чому синтаксис здається важче прочитати, це те, що в ньому відсутні деякі неявні дужки, що робить приклад зовнішнім виглядом і важче зрозуміти. Редагування прикладу для додавання дужок.
Говінд Рай

1
Перший метод спрацював ідеально для мене, дякую
Ліран Н

86

Ось альтернатива.

var condition = true;

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

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

Або його вбудована версія

var condition = true;

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

9
Мені подобається такий підхід, він робить мене крутим серед моїх однокласників. Не відступаючи від цього, реквізит зрештою передається як пара ключових значень, це правильно?
JohnnyQ

1
Якщо conditionзначення false, це спробує розширити / повторити значення false, що, на мою думку, не є правильним.
Lars Nyström

1
@ LarsNyström, Це має сенс. Оператор розповсюдження приймає лише ітерабелі, де falseїх немає. Просто зверніться до Вавілони. Це працює з нею, коли вона conditionоцінюється як хибна, оскільки Babel реалізує оператора. Хоча тривіальне вирішення може бути ...( condition ? { disabled: true } : {} ), воно стає дещо багатослівним. Дякуємо за цей приємний внесок!
Сезон

+1 Цей підхід необхідний, якщо ви хочете умовно виводити data-*або aria-*атрибути, оскільки вони є особливим випадком у JSX, тому data-my-conditional-attr={ false }він виводить, data-my-conditional-attr="false"а не опускає атрибут. facebook.github.io/react/docs/dom-elements.html
ptim

32

Ось як я це роблю.

При умовному :

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

Я все ще вважаю за краще використовувати звичайний спосіб передачі реквізиту вниз, тому що він легше читається (на мою думку) у випадку, якщо він не має жодних умов.

Без умовного :

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

Не могли б ви пояснити, як працює ця частина - ...(tooltip && { tooltip }),? Це працює на компоненті, але коли я намагаюся використовувати щось подібне у коді, я отримую помилку, тобто намагаюся поширити неітерабельне значення
skwisgaar

ймовірно, тому falseyValue && {}, що повернеться неправдивим, тому, ймовірно, ви поширюєтесь на помилкових, наприклад ...(false). набагато краще використовувати повний вираз, щоб розповсюдження продовжувало вести себе ...(condition ? {foo: 'bar'} : {})
lfender6445

19

Ви можете використовувати той самий ярлик, який використовується для додавання / видалення (частин) компонентів ( {isVisible && <SomeComponent />}).

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

3
Якщо someConditionце правда, але someValueпомилково (наприклад, falseсам, або 0, і т.д.), атрибут все ж включається? Це важливо, якщо необхідно чітко включити хибне значення, наприклад, 0атрибут координати тощо.
Ендрю Віллемс

Зазвичай атрибут опущений, але не у випадку, data-*і aria-*, дивіться мій коментар вище. Якщо ви цитуєте значення або передаєте це як String, атрибут відображатиметься: напр., someAttr={ `${falsyValue}` }Може візуалізуватиsomeAttr="false"
ptim

19

Скажімо, ми хочемо додати спеціальну властивість (використовуючи aria- * або data- *), якщо умова відповідає:

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

Скажімо, ми хочемо додати властивість стилю, якщо умова справжня:

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

10

Якщо ви використовуєте ECMAScript 6, ви можете просто написати так.

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

7

Це має спрацювати, оскільки ваш стан зміниться після виклику Ajax, а батьківський компонент повторно відобразиться.

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

3

У React ви можете умовно надати компоненти, але також їх атрибути, такі як реквізит, className, id тощо.

У React дуже хороша практика використовувати потрійний оператор, який може допомогти вам умовно візуалізувати компоненти.

Приклад також показує, як умовно візуалізувати Компонент та його атрибут стилю.

Ось простий приклад:

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>


Це може стати справді безладним з великою кількістю атрибутів. Мені більше подобається варіант поширення.
Remi Sture

Так, ти маєш рацію, але це для того, хто потребує огляду, я зроблю ще один приклад. Але хочете, щоб справи були простими.
Юрай

0

Розглядаючи посаду JSX In Depth , ви можете вирішити свою проблему таким чином:

if (isRequired) {
  return (
    <MyOwnInput name="test" required='required' />
  );
}
return (
    <MyOwnInput name="test" />
);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.