Как условно добавить атрибуты в компоненты 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 файла.

juandemarco
источник
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} />
    );
  }
}
GijsjanB
источник
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}} />
snyh
источник
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" />
);
Виктор Киреев
источник