【问题标题】:How do I conditionally add attributes to React components?如何有条件地向 React 组件添加属性?
【发布时间】:2016-08-01 23:13:09
【问题描述】:

有没有办法只在满足特定条件时才向 React 组件添加属性?

我应该在渲染后基于 Ajax 调用向表单元素添加 required 和 readOnly 属性,但我看不出如何解决这个问题,因为readOnly="false" 与完全省略该属性不同。

下面的例子应该解释我想要什么,但它不起作用。

(解析错误:意外的标识符)

function MyInput({isRequired}) {
  return <input classname="foo" {isRequired ? "required" : ""} />
}

【问题讨论】:

  • 可能是一条评论对某人有帮助,我发现 React 16.7 doesnt rerenders 如果您仅在商店中更改了组件的 html 属性,则更新组件的 html 属性(fe redux) 并绑定到组件。这意味着组件具有 fearia-modal=true,您将更改(为 false)推送到 aria/data 属性的存储区,但没有其他任何更改(例如组件的内容或类或变量) ) 结果 ReactJs 不会更新该组件中的 aria/data attrs。我一直在搞砸一整天才意识到这一点。

标签: javascript reactjs


【解决方案1】:

这应该可以工作,因为您的状态会在 Ajax 调用后发生变化,并且父组件将重新渲染。

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

【讨论】:

    【解决方案2】:

    显然,对于某些属性,如果您传递给它的值不真实,React 足够智能,可以忽略该属性。例如:

    const InputComponent = function() {
        const required = true;
        const disabled = false;
    
        return (
            <input type="text" disabled={disabled} required={required} />
        );
    }
    

    将导致:

    <input type="text" required>
    

    更新:如果有人对这种情况的发生方式/原因感到好奇,您可以在 ReactDOM 的源代码中找到详细信息,特别是在 DOMProperty.js 文件的 30167 行中。

    【讨论】:

    • 一般null 的意思是“就像我根本没有指定它一样”。对于布尔 dom 属性,true/false 优于重复属性名称/false,例如&lt;input disabled&gt; 编译为 React.createElement('input', {disabled: true})
    • readonly 永远不会被添加,因为 React 需要属性 readOnly(大写 O)。
    • 谢谢!确保该值不只是一个空字符串或零,这些可能不会被删除。例如,您可以传递一个这样的值,如果它的计算结果为 false,它应该确保它被删除:alt={props.alt || null}
    • 谢谢,@Jake。我曾尝试将属性设置为false,但只有null 确保该属性实际上已被删除。
    • 我收到Warning: Received `false` for a non-boolean attribute `active`...
    【解决方案3】:

    考虑到帖子JSX In Depth,你可以这样解决你的问题:

    if (isRequired) {
      return (
        <MyOwnInput name="test" required='required' />
      );
    }
    return (
        <MyOwnInput name="test" />
    );
    

    【讨论】:

      【解决方案4】:

      juandemarco's answer 通常是正确的,但这里有另一种选择。

      按照你喜欢的方式构建一个对象:

      var inputProps = {
        value: 'foo',
        onChange: this.handleChange
      };
      
      if (condition)
        inputProps.disabled = true;
      

      使用传播进行渲染,也可以选择传递其他道具。

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

      【讨论】:

      • 这实际上非常有用,尤其是在有条件地添加许多属性时(我个人不知道可以这样做)。
      • 很优雅,但不应该是 inputProps.disabled = true 吗?
      • 很简单,我的代码在没有多个条件的情况下更具可读性。
      • 如果有人关心这个“糖”的精确语义,你可以看看你的 .jsx 被转译成的脚本,你会看到一个函数 _extends 已添加到其中,这将(在正常情况下)采用从“正常属性”构造的props 并应用Object.assign(props, inputProps)
      【解决方案5】:

      这是一个通过React-Bootstrap(版本0.32.4)使用BootstrapButton的示例:

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

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


      基于Andy Polhill's comment的另一种方式:

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

      唯一的小区别是,在第二个示例中,内部组件&lt;Button/&gt;props 对象将有一个键bsStyle,其值为undefined

      【讨论】:

      • @Punit,扩展运算符的优先级低于条件运算符,因此首先评估条件({bsStyle: 'success'}{} 由它得出),然后扩展该对象。
      • 下面会不会做同样的&lt;Button bsStyle={ condition ? 'success': undefined } /&gt; 我发现语法稍微容易一些,传递undefined 将省略该属性。
      • @AndyPolhill 对我来说看起来不错并且更容易阅读代码,唯一的小区别是在您的代码示例内部组件 &lt;Button/&gt;props 对象将有一个键 bsStyle值为undefined
      • 第一种方法对我来说效果很好,谢谢
      • 非常简单易行的方法
      【解决方案6】:

      您可以使用相同的快捷方式,用于添加/删除(部分)组件 ({isVisible &amp;&amp; &lt;SomeComponent /&gt;})。

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

      【讨论】:

      • 如果someCondition 为真但someValue 为假(例如false 本身或0 等),该属性是否仍被包含在内?如果有必要明确包含一个虚假值,这很重要,例如0 用于坐标属性等
      • 一般情况下,属性会被省略,但data-*aria-*的情况下不会,见我上面的评论。如果您引用该值,或将其转换为字符串,则该属性将显示:例如 someAttr={ `${falsyValue}` } could render someAttr="false"
      【解决方案7】:

      这是另一种选择。

      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 } ) } />
      );
      

      【讨论】:

      • 我喜欢这种方法,它让我在同事中很酷。开个玩笑,从表面上看,props 只是作为键值对传递的,对吗?
      • 如果condition 为假,这将尝试扩展/迭代假,我认为这是不正确的。
      • @LarsNyström,这是有道理的。扩展运算符只接受迭代,其中false 不是一个。只需与 Babel 核对即可。当 condition 评估为 false 时,这适用于它,因为 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
      【解决方案8】:

      假设如果条件为真,我们想添加一个自定义属性(使用 aria-* 或 data-*):

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

      假设我们要在条件为真时添加样式属性:

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

      【讨论】:

        【解决方案9】:

        如果您使用 ECMAScript 6,您可以像这样简单地编写。

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

        【讨论】:

        【解决方案10】:

        在 React 中,您可以有条件地渲染组件,还可以渲染它们的属性,例如 props、className、id 等等。

        在 React 中,使用 ternary operator 是非常好的做法,它可以帮助您有条件地渲染组件。

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

        这是一个简单的例子:

        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>

        【讨论】:

        • 这会因为很多属性而变得非常混乱。我更喜欢传播变体。
        • 是的,你是对的,但这是为需要了解概览的人准备的,我将再举一个例子。但要保持简单。
        【解决方案11】:

        这是我的做法。

        带条件

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

        我仍然更喜欢使用常规的方式传递 props,因为在没有任何条件的情况下(在我看来)它更具可读性。

        没有条件

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

        【讨论】:

        • 您能否解释一下这部分的工作原理 - ...(tooltip &amp;&amp; { tooltip }),?它确实适用于组件,但是当我尝试在代码中使用类似的东西时,我得到一个错误,这意味着我试图传播不可迭代的值
        • 可能是因为falseyValue &amp;&amp; {} 会返回false,所以很可能您在传播虚假信息,例如...(false)。使用完整表达式要好得多,因此传播继续表现...(condition ? {foo: 'bar'} : {})
        【解决方案12】:

        例如使用自定义容器的属性样式

        const DriverSelector = props => {
          const Container = props.container;
          const otherProps = {
            ...( props.containerStyles && { style: props.containerStyles } )
          };
        
          return (
            <Container {...otherProps} >
        

        【讨论】:

          【解决方案13】:

          在我看来,管理多个条件 props 的最佳方法是 @brigand 的 props object 方法。但可以对其进行改进以避免为每个条件属性添加一个if 块。

          ifVal 助手

          随意重命名 (iv, condVal, cv, _, ...)

          如果满足条件,您可以定义一个辅助函数来返回一个值或另一个值:

          // components-helpers.js
          export const ifVal = (cond, trueValue=true, falseValue=null) => {
            return cond ? trueValue : falseValue
          }
          

          如果condtrue(或truthy),则返回trueValue - 或true。 如果condfalse(或falsy),则返回falseValue - 或null

          这些默认值(truenull)通常是允许将 prop 传递或不传递给 React 组件的正确值。您可以将此函数视为“改进的 React 三元运算符”。如果您需要对返回值进行更多控制,请对其进行改进。

          让我们将它与许多道具一起使用。

          构建(复杂的)道具对象

          // your-code.js
          import { ifVal } from './components-helpers.js'
          
          // BE SURE to replace all true/false with a real condition in you code
          // this is just an example
          
          const inputProps = {
            value: 'foo',
            enabled: ifVal(true), // true
            noProp: ifVal(false), // null - ignored by React
            aProp: ifVal(true, 'my value'), // 'my value'
            bProp: ifVal(false, 'the true text', 'the false text') // 'my false value',
            onAction: ifVal(isGuest, handleGuest, handleUser) // it depends on isGuest value
          };
          
           <MyComponent {...inputProps} />
          

          这种方法类似于使用classnames utility 有条件地管理类的流行方法,但适用于道具。

          为什么要使用这种方法

          即使有许多条件 props,您也将拥有清晰易读的语法:每个新 prop 只需在对象声明中添加一行代码。

          通过这种方式,您可以替换重复运算符(...&amp;&amp;? :,...)的语法噪音,当您有很多道具时,这可能会非常烦人,使用简单的函数调用。

          作为开发人员,我们的首要任务是编写最显而易见的代码来解决问题。 太多次我们为我们的自我解决问题,在不需要的地方增加了复杂性。 我们的代码应该简单明了,对我们今天、明天对我们和我们的伙伴来说都是如此。

          仅仅因为我们可以做某事并不意味着我们应该做某事

          我希望这个迟到的回复会有所帮助。

          【讨论】:

          • 非常整洁!我很惊讶为什么这个答案没有投票!
          【解决方案14】:

          我认为这可能对那些希望属性值成为函数的人有用:

          import { RNCamera } from 'react-native-camera';
          [...]
          
          export default class MyView extends React.Component {
          
              _myFunction = (myObject) => {
                  console.log(myObject.type); //
              }
          
              render() {
          
                  var scannerProps = Platform.OS === 'ios' ? 
                  {
                      onBarCodeRead : this._myFunction
                  } 
                  : 
                  { 
                      // here you can add attribute(s) for other platforms
                  }
          
                  return (
                      // it is just a part of code for MyView's layout
                      <RNCamera 
                          ref={ref => { this.camera = ref; }}
                          style={{ flex: 1, justifyContent: 'flex-end', alignItems: 'center', }}
                          type={RNCamera.Constants.Type.back}
                          flashMode={RNCamera.Constants.FlashMode.on}
                          {...scannerProps}
                      />
                  );
              }
          }
          

          【讨论】:

            【解决方案15】:

            使用undefined 适用于大多数属性:

            const name = "someName";
            
            return (
                <input name={name ? name : undefined} />
            );
            

            【讨论】:

              【解决方案16】:

              在 React 中,我们将值作为 Props 从父组件传递到子组件。如果该值为 false,则不会将其作为 props 传递。同样在某些情况下,我们也可以使用三元(条件运算符)。

              【讨论】:

                【解决方案17】:
                <input checked={true} type="checkbox"  />
                

                【讨论】:

                • 几乎完美。不过,细节太少了;-)。将投票作为您的第一个答案!干得好!
                【解决方案18】:

                简单的方法

                const InputText= (required = false , disabled = false) => 
                         (<input type="text" disabled={disabled} required={required} />);
                

                如果您希望它是真实的,就可以像这样使用它

                <InputText required disabled/>
                

                【讨论】:

                  【解决方案19】:
                  1. 对于 React [1] 列出的一些布尔属性:
                  <input disabled={disabled} />
                  
                  // renders either `<input>` or `<input disabled>` 
                  
                  1. 对于其他属性:
                  <div aria-selected= {selected ? "" : undefined} />
                  
                  // renders either `<div aria-selected></div>` or `<div></div>`
                  

                  [1]布尔属性列表:https://github.com/facebook/react/blob/3f9480f0f5ceb5a32a3751066f0b8e9eae5f1b10/packages/react-dom/src/shared/DOMProperty.js#L318-L345

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2015-07-04
                    • 2022-11-18
                    • 1970-01-01
                    • 2020-06-03
                    • 2021-01-21
                    • 2019-04-13
                    相关资源
                    最近更新 更多