Как условно добавить атрибуты в компоненты React?


551

Есть ли способ добавить атрибуты в компонент 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 aria-modal=true, вы помещаете изменения (в false) в хранилище атрибутов aria / data , но ничего больше не изменяется (например, содержимое компонента или класс или переменные в нем), так как в результате ReactJ не будет обновлять aria / атрибуты данных в этих компонентах. Я целый день возился с этим, чтобы понять это.
— АлексНиконов

Ответы:


535

Очевидно, для определенных атрибутов 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
Спасибо, Джейк. Я попытался установить атрибут false, но только nullудостоверился, что атрибут был фактически удален.
— Натан Артур

387

Ответ Хуандемарко, как правило, правильный, но здесь есть другой вариант.

Постройте объект так, как вам нравится:

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

if (condition)
  inputProps.disabled = true;

Рендеринг со спредом, при желании можно передать и другие реквизиты.

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

14
Это на самом деле очень полезно, особенно при условном добавлении многих свойств (и я лично понятия не имел, что это можно сделать таким образом).
— июня

1
Очень элегантно, но не должно ли это быть inputProps.disabled = true?
— Джоппе

очень просто, я сделал мой код более читабельным, не имея нескольких условий.
— Навин Кумар 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, что я не считаю правильным.
— Ларс Нистрем

1
@ LarsNyström, это имеет смысл. Оператор распространения принимает только итерации, где falseне один. Просто посоветуйтесь с Бабелем. Это работает с ним, когда conditionоценивается как ложное, поскольку Бабель реализует оператор. Хотя тривиальный обходной путь может быть ...( 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и т. Д.), Атрибут все еще включается? Это важно, если необходимо явно включить ложное значение, например, a 0для атрибута координаты и т. Д.
— Эндрю Виллемс

Обычно атрибут пропускается, но не в случае data-*и aria-*, см. Мой комментарий выше. Если вы заключите значение в кавычки или приведете его в виде строки, атрибут будет отображаться: например, 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}} />

6

Это должно работать, так как ваше состояние изменится после вызова Ajax, а родительский компонент будет перерисован.

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

3

В React вы можете условно визуализировать Компоненты, а также их атрибуты, такие как props, 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>


Это может сильно испортить множество атрибутов. Мне больше нравится вариант распространения.
— Реми Стуре

Да. Вы правы, но для кого-то, кому нужно получить обзор, я приведу другой пример. Но хочу, чтобы все было просто.
— Юрай

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.