如何有条件地向React组件添加属性?


547

如果满足特定条件,是否有办法仅将属性添加到R​​eact组件?

我应该在渲染后基于Ajax调用将required和readOnly属性添加到表单元素中,但是由于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,您将更改(为false)推送到aria / data属性存储,但其他没有更改(例如组件的内容或其中的类或变量),因为结果ReactJs不会更新aria / 该组件中的数据属性。我整天都在忙着意识到这一点。
AlexNikonov

Answers:


533

显然,对于某些属性,如果您传递给它的值不真实,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的源代码中找到详细信息,特别是在DOMProperty.js文件的第30167行。


45
通常null表示“行为就像我完全没有指定”。对于布尔dom属性,与重复属性名称/ false相比,优先选择true / 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确保确实删除了该属性。
内森·亚瑟

385

juandemarco的答案通常是正确的,但这是另一种选择。

用自己喜欢的方式构建对象:

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

if (condition)
  inputProps.disabled = true;

以传播方式渲染,也可以选择通过其他道具。

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

13
这实际上非常有用,特别是在有条件地添加许多属性时(我个人不知道可以用这种方式完成)。
juandemarco

1
非常优雅,但不应该将其设置为inputProps.disabled = true吗?
2013年

非常简单,我在没有多个条件的情况下使代码更具可读性。
Naveen Kumar PG,

如果关于这个精确语义有人关心“糖”,你可以看剧本,你.jsx被transpiled到你会看到一个功能_extends已经被添加到它,这将(正常情况下)采取props从构建“常规属性”并应用Object.assign(props, inputProps)
内森·查佩尔

298

下面是使用的示例自举Button经由阵营的自举(版本0.32.4):

var condition = true;

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

根据条件,将返回{bsStyle: 'success'}{}。然后,散布运算符会将返回的对象的属性散布到Button组件。在虚假情况下,由于返回的对象上不存在任何属性,因此不会将任何内容传递给组件。


根据安迪·波希尔(Andy Polhill)的评论的另一种方法:

var condition = true;

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

唯一的区别是在第二个示例中,内部组件<Button/>props对象将具有bsStyle一个值为的键undefined


5
@Punit,传播运算符的优先级比条件运算符的优先级低,因此先评估条件({bsStyle: 'success'}{}从中得出结果),然后传播该对象。
维克多·扎曼尼亚

5
下面的操作是否相同? <Button bsStyle={ condition ? 'success': undefined } /> 我发现语法稍微容易些,传递undefined将忽略该属性。
安迪·波希尔

3
@AndyPolhill对我来说看起来不错,并且更容易阅读代码,唯一的不同是,在代码示例中,内部组件<Button/>props对象将具有bsStyle值为的键undefined
Arman Yeghiazaryan

@AndyPolhill语法似乎更难阅读的原因是因为它缺少一些隐式括号,这使该示例看起来很陌生并且更难以理解。编辑示例以添加括号。
Govind Rai

1
第一种方法对我来说效果很好,谢谢
Liran H

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为假,则将尝试扩展/迭代为假,我认为这是不正确的。
拉尔斯·尼斯特罗姆(LarsNyström)

1
@LarsNyström,这很有道理。点差运算符仅接受可迭代项,而false不是一个。只需与Babel确认。condition由于Babel实现运算符的方式,在评估为false 时,此方法可以使用。尽管可能有一个微不足道的解决方法...( 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,所以它很可能传播了false,例如...(false)。使用完整表达式要好得多,因此传播会继续 ...(condition ? {foo: 'bar'} : {})
起作用

19

您可以使用相同的快捷方式,该快捷方式用于添加/删除组件(的一部分{isVisible && <SomeComponent />})()。

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

3
如果someCondition为true,但someValue为假(例如false本身或0,等等),该属性是否仍包含在内?这是重要的,如果有必要明确包括falsy值,例如0用于坐标属性,等等
安德鲁·威廉姆斯

通常情况下,该属性被省略,但不是在的情况下,data-*aria-*,请看我上面的评论。如果您引用该值或将其someAttr={ `${falsyValue}` }someAttr="false"
强制转换

19

假设我们想在条件为真的情况下添加自定义属性(使用aria- *或data- *):

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

假设我们想在条件为true的情况下添加样式属性:

{...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中,您可以有条件地渲染Components,还可以渲染它们的属性,例如props,className,id等。

在React中,使用三元运算符是一种很好的做法它可以帮助您有条件地渲染Components。

一个示例还显示了如何有条件地渲染Component及其样式属性。

这是一个简单的示例:

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

是的您是正确的,但这是给需要概述的人的,我将再举一个例子。但是要保持简单。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.