如何拥有条件元素并使用Facebook React的JSX保持干净?

时间:2014-03-20 16:03:34

标签: javascript reactjs react-jsx

如何选择在JSX中包含元素?下面是一个使用横幅的示例,如果已经传入,该横幅应该在组件中。我想避免的是必须在if语句中复制HTML标记。

render: function () {
    var banner;
    if (this.state.banner) {
        banner = <div id="banner">{this.state.banner}</div>;
    } else {
        banner = ?????
    }
    return (
        <div id="page">
            {banner}
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

27 个答案:

答案 0 :(得分:148)

将横幅保留为未定义且不包括在内。

答案 1 :(得分:129)

这个怎么样?让我们定义一个简单的帮助If组件。

var If = React.createClass({
    render: function() {
        if (this.props.test) {
            return this.props.children;
        }
        else {
            return false;
        }
    }
});

并以这种方式使用它:

render: function () {
    return (
        <div id="page">
            <If test={this.state.banner}>
                <div id="banner">{this.state.banner}</div>
            </If>
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

更新:随着我的回答变得越来越流行,我觉得有必要提醒您注意与此解决方案相关的最大危险。正如另一个答案所指出的,<If />组件内的代码总是被执行,无论条件是真还是假。因此,如果bannernull,则以下example将失败(请注意第二行的属性访问权限):

<If test={this.state.banner}>
    <div id="banner">{this.state.banner.url}</div>
</If>

使用它时必须小心。我建议阅读替代(更安全)方法的其他答案。

更新2:回顾过去,这种做法不仅危险,而且非常繁琐。这是一个典型的例子,当一个开发人员(我)试图将他知道的模式和方法从一个区域转移到另一个区域但是它确实不起作用(在这种情况下是其他模板语言)。

如果您需要条件元素,请按以下步骤操作:

render: function () {
    return (
        <div id="page">
            {this.state.banner &&
                <div id="banner">{this.state.banner}</div>}
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

如果你还需要else分支,只需使用三元运算符:

{this.state.banner ?
   <div id="banner">{this.state.banner}</div> :
   <div>There is no banner!</div>
}

它更短,更优雅,更安全。我用它所有的时间。唯一的缺点是你不能轻易地进行else if分支,但这通常不常见。

无论如何,这要归功于JavaScript中的logical operators工作方式。逻辑运算符甚至允许这样的小技巧:

<h3>{this.state.banner.title || 'Default banner title'}</h3>

答案 2 :(得分:81)

就个人而言,我认为http://facebook.github.io/react/tips/if-else-in-JSX.html中显示的三元表达式是符合ReactJs标准的最自然的方式。

请参阅以下示例。乍一看有点乱,但效果很好。

<div id="page">
  {this.state.banner ? (
    <div id="banner">
     <div class="another-div">
       {this.state.banner}
     </div>
    </div>
  ) : 
  null} 
  <div id="other-content">
    blah blah blah...
  </div>
</div>

答案 3 :(得分:44)

你也可以像

那样写
{ this.state.banner && <div>{...}</div> }

如果您的state.bannernullundefined,则会跳过条件的右侧。

答案 4 :(得分:40)

If样式组件很危险,因为代码块始终执行,无论条件如何。例如,如果bannernull

,则会导致空异常
//dangerous
render: function () {
  return (
    <div id="page">
      <If test={this.state.banner}>
        <img src={this.state.banner.src} />
      </If>
      <div id="other-content">
         blah blah blah...
      </div>
    </div>
  );
}

另一种选择是使用内联函数(对else语句特别有用):

render: function () {
  return (
    <div id="page">
      {function(){
        if (this.state.banner) {
          return <div id="banner">{this.state.banner}</div>
        }
      }.call(this)}
      <div id="other-content">
         blah blah blah...
      </div>
    </div>
  );
}

来自issues的另一个选项:

render: function () {
  return (
    <div id="page">
      { this.state.banner &&
        <div id="banner">{this.state.banner}</div>
      }
      <div id="other-content">
         blah blah blah...
      </div>
    </div>
  );
}

答案 5 :(得分:22)

&安培;&安培; +代码风格+小组件

这个简单的测试语法+代码风格约定+小型聚焦组件对我来说是最具可读性的选择。您只需要特别注意false0""等虚假值。

render: function() {
    var person= ...; 
    var counter= ...; 
    return (
       <div className="component">
          {person && (
            <Person person={person}/>
          )}
          {(typeof counter !== 'undefined') && (
            <Counter value={counter}/>
          )}
       </div>
    );
}

做符号

ES7 stage-0表示法语法也非常好,当我的IDE正确支持时,我肯定会使用它:

const Users = ({users}) => (
  <div>
    {users.map(user =>
      <User key={user.id} user={user}/>
    )}
  </div>
)  

const UserList = ({users}) => do {
  if (!users) <div>Loading</div>
  else if (!users.length) <div>Empty</div>
  else <Users users={users}/>
}

此处有更多详情:ReactJs - Creating an "If" component... a good idea?

答案 6 :(得分:21)

简单,创建一个功能。

  %d, %i  A decimal number (the integer part).

  %s      A character string.

这是我个人一直关注的模式。使代码真正干净,易于理解。如果它变得太大(或在其他地方重复使用),它还允许您将renderBanner: function() { if (!this.state.banner) return; return ( <div id="banner">{this.state.banner}</div> ); }, render: function () { return ( <div id="page"> {this.renderBanner()} <div id="other-content"> blah blah blah... </div> </div> ); } 重构为自己的组件。

答案 7 :(得分:13)

实验性的ES7 do语法使这很容易。如果您正在使用Babel,请启用es7.doExpressions功能:

render() {
  return (
    <div id="banner">
      {do {
        if (this.state.banner) {
          this.state.banner;
        } else {
          "Something else";
        }
      }}
    </div>
  );
}

请参阅http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions

答案 8 :(得分:11)

正如答案中已经提到的,JSX为您提供了两个选项

  • 三元运算符

    { this.state.price ? <div>{this.state.price}</div> : null }

  • 逻辑连接

    { this.state.price && <div>{this.state.price}</div> }

但是,那些不适合 price == 0的人。

JSX将在第一种情况下呈现false分支,如果是逻辑连接,则不会呈现任何内容。如果属性可能为0,则只需在JSX之外使用if语句。

答案 9 :(得分:8)

当你在里面有多个元素时,这个组件可以工作,如果&#34;分支:

    var Display = React.createClass({
        render: function() {
            if (!this.props.when) {
                return false;
            }
            return React.DOM.div(null, this.props.children);
        }
    });

用法:

      render: function() {
            return (
                <div>
                    <Display when={this.state.loading}>
                        Loading something...
                        <div>Elem1</div>
                        <div>Elem2</div>
                    </Display>
                    <Display when={!this.state.loading}>
                        Loaded
                        <div>Elem3</div>
                        <div>Elem4</div>
                    </Display>
                </div>
            );
        },

P.S。有人认为这些组件不适合代码阅读。但在我看来,使用javascript的html更糟糕

答案 10 :(得分:3)

大多数示例都有一行&#34; html&#34;有条件地呈现。当我有多条需要有条件渲染的行时,这对我来说似乎是可读的。

render: function() {
  // This will be renered only if showContent prop is true
  var content = 
    <div>
      <p>something here</p>
      <p>more here</p>
      <p>and more here</p>
    </div>;

  return (
    <div>
      <h1>Some title</h1>

      {this.props.showContent ? content : null}
    </div>
  );
}

第一个示例很好,因为我们可以有条件地呈现其他内容,例如null

,而不是{this.props.showContent ? content : otherContent}

但是,如果您只是需要显示/隐藏内容,那么自Booleans, Null, and Undefined Are Ignored

以来情况就更好了
render: function() {
  return (
    <div>
      <h1>Some title</h1>

      // This will be renered only if showContent prop is true
      {this.props.showContent &&
        <div>
          <p>something here</p>
          <p>more here</p>
          <p>and more here</p>
        </div>
      }
    </div>
  );
}

答案 11 :(得分:2)

还有另一种解决方案,if component for React

var Node = require('react-if-comp');
...
render: function() {
    return (
        <div id="page">
            <Node if={this.state.banner}
                  then={<div id="banner">{this.state.banner}</div>} />
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

答案 12 :(得分:2)

我使用更明确的快捷方式:立即调用的函数表达式(IIFE):

{(() => {
  if (isEmpty(routine.queries)) {
    return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
  } else if (this.state.configured) {
    return <DeviceList devices={devices} routine={routine} configure={() => this.setState({configured: false})}/>
  } else {
    return <Grid devices={devices} routine={routine} configure={() => this.setState({configured: true})}/>
  }
})()}

答案 13 :(得分:1)

我最近做了https://github.com/ajwhite/render-if,只有在谓词通过时才能安全地渲染元素

{renderIf(1 + 1 === 2)(
  <span>Hello!</span>
)}

const ifUniverseIsWorking = renderIf(1 + 1 === 2);

//...

{ifUniverseIsWorking(
  <span>Hello!</span>
)}

答案 14 :(得分:1)

还有一个非常干净的单行版本...... {this.props.product.title || &#34;没有标题&#34; }

即:

render: function() {
            return (
                <div className="title">
                    { this.props.product.title || "No Title" }
                </div>
            );
        }

答案 15 :(得分:1)

您可以使用三元运算符有条件地包含元素,如下所示:

render: function(){

         return <div id="page">

                  //conditional statement
                  {this.state.banner ? <div id="banner">{this.state.banner}</div> : null}

                  <div id="other-content">
                      blah blah blah...
                  </div>

               </div>
}

答案 16 :(得分:1)

您可以使用函数并返回组件并保持渲染函数的精简

class App extends React.Component {
  constructor (props) {
    super(props);
    this._renderAppBar = this._renderAppBar.bind(this);
  }

  render () {
    return <div>
      {_renderAppBar()}

      <div>Content</div>

    </div>
  }

  _renderAppBar () {
    if (this.state.renderAppBar) {
      return <AppBar />
    }
  }
}

答案 17 :(得分:1)

我使https://www.npmjs.com/package/jsx-control-statements更容易一些,基本上它允许您将<If>条件定义为标记,然后将它们编译为三元ifs,以便仅在<If>内的代码如果条件为真,则执行。

答案 18 :(得分:1)

这是我使用ES6的方法。

import React, { Component } from 'react';
// you should use ReactDOM.render instad of React.renderComponent
import ReactDOM from 'react-dom';

class ToggleBox extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // toggle box is closed initially
      opened: false,
    };
    // http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html
    this.toggleBox = this.toggleBox.bind(this);
  }

  toggleBox() {
    // check if box is currently opened
    const { opened } = this.state;
    this.setState({
      // toggle value of `opened`
      opened: !opened,
    });
  }

  render() {
    const { title, children } = this.props;
    const { opened } = this.state;
    return (
      <div className="box">
        <div className="boxTitle" onClick={this.toggleBox}>
          {title}
        </div>
        {opened && children && (
          <div class="boxContent">
            {children}
          </div>
        )}
      </div>
    );
  }
}

ReactDOM.render((
  <ToggleBox title="Click me">
    <div>Some content</div>
  </ToggleBox>
), document.getElementById('app'));

演示:http://jsfiddle.net/kb3gN/16688/

我使用的代码如下:

{opened && <SomeElement />}

仅当SomeElement为真时才会呈现opened。它的工作原理是JavaScript解析逻辑条件的方式:

true && true && 2; // will output 2
true && false && 2; // will output false
true && 'some string'; // will output 'some string'
opened && <SomeElement />; // will output SomeElement if `opened` is true, will output false otherwise

由于React将忽略false,我发现有条件地呈现某些元素是非常好的方法。

答案 19 :(得分:1)

也许它可以帮助遇到问题的人:All the Conditional Renderings in React这是一篇关于React中条件渲染的所有不同选项的文章。

何时使用哪种条件渲染的关键要点:

** if-else

  • 是最基本的条件渲染
  • 初学者友善
  • 使用if返回null
  • 从渲染方法中提前选择退出

**三元运算符

  • 将其用于if-else语句
  • 它比if-else
  • 更简洁

**逻辑&amp;&amp;操作

  • 当三元操作的一侧返回null时使用它

**开关案例

  • 详细
  • 只能使用自动调用功能
  • 进行内联
  • 避免使用枚举

**枚举

  • 完美地映射不同的状态
  • 完美地映射多个条件

**多级/嵌套条件渲染

  • 为了便于阅读而避免使用它们
  • 使用自己的简单条件渲染将组件拆分为更轻量级的组件
  • 使用HOC

** HOCs

  • 使用它们来屏蔽条件渲染
  • 组件可以专注于其主要目的

**外部模板组件

  • 避免使用它们并熟悉JSX和JavaScript

答案 20 :(得分:1)

使用ES6,您可以使用简单的单行

来完成
const If = ({children, show}) => show ? children : null

&#34;显示&#34;是一个布尔值,您可以通过

使用此类
<If show={true}> Will show </If>
<If show={false}> WON'T show </div> </If>

答案 21 :(得分:0)

我不认为这已被提及。这就像你自己的答案,但我认为它更简单。您总是可以从表达式返回字符串,并且可以在表达式中嵌入jsx,因此这样可以轻松读取内联表达式。

render: function () {
    return (
        <div id="page">
            {this.state.banner ? <div id="banner">{this.state.banner}</div> : ''}
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

&#13;
&#13;
<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpf1/t39.3284-6/10574688_1565081647062540_1607884640_n.js"></script>
<script src="http://dragon.ak.fbcdn.net/hphotos-ak-xpa1/t39.3284-6/10541015_309770302547476_509859315_n.js"></script>
<script type="text/jsx;harmony=true">void function() { "use strict";

var Hello = React.createClass({
  render: function() {
    return (
      <div id="page">
        {this.props.banner ? <div id="banner">{this.props.banner}</div> : ''}
        <div id="other-content">
          blah blah blah...
        </div>
      </div>
    );   
  }
});

var element = <div><Hello /><Hello banner="banner"/></div>;
React.render(element, document.body);

}()</script>
&#13;
&#13;
&#13;

答案 22 :(得分:0)

我喜欢立即调用函数表达式(IIFE)和if-elserender callbacksternary operators的明确性。

render() {
  return (
    <div id="page">
      {(() => (
        const { banner } = this.state;
        if (banner) {
          return (
            <div id="banner">{banner}</div>
          );
        }
        // Default
        return (
          <div>???</div>
        );
      ))()}
      <div id="other-content">
        blah blah blah...
      </div>
    </div>
  );
}

你只需要熟悉IIFE语法,{expression}是通常的React语法,在它里面只考虑你正在编写一个调用自身的函数。

function() {

}()

需要包裹在parens中

(function() {

}())

答案 23 :(得分:0)

还有一种使用渲染道具来条件渲染组件的技术。它的好处是在满足条件之前不会评估渲染,因此不必担心 null 未定义的值。

const Conditional = ({ condition, render }) => {
  if (condition) {
    return render();
  }
  return null;
};

class App extends React.Component {
  constructor() {
    super();
    this.state = { items: null }
  }

  componentWillMount() {
    setTimeout(() => { this.setState({ items: [1,2] }) }, 2000);
  }

  render() {
    return (
      <Conditional
        condition={!!this.state.items}
        render={() => (
          <div>
            {this.state.items.map(value => <p>{value}</p>)}
          </div>
        )}
      />
    )
  }
}

答案 24 :(得分:0)

如果传递条件已满,则必须仅渲染某些内容时,可以使用语法:

{ condition && what_to_render }

这种方式的代码如下所示:

render() {
    const { banner } = this.state;
    return (
        <div id="page">
            { banner && <div id="banner">{banner}</div> }
            <div id="other-content">
                blah blah blah...
            </div>
        </div>
    );
}

当然,还有其他有效的方法可以做到这一点,这完全取决于偏好和场合。如果您有兴趣,可以在this article中了解有关如何在React中进行条件渲染的更多方法!

答案 25 :(得分:0)

我只是在 React 和 TypeScript 中使用以下代码片段

export default function ReactIf(props: {condition: boolean, children: React.ReactNode }) {
    return props.condition ? <React.Fragment>{props.children}</React.Fragment> : <React.Fragment/>;
}

答案 26 :(得分:-1)

只是添加另一个选项 - 如果您喜欢/容忍咖啡脚本,您可以使用coffee-react来编写JSX,在这种情况下if / else语句是可用的,因为它们是coffee-script中的表达式而不是语句:

render: ->
  <div className="container">
    {
      if something
        <h2>Coffeescript is magic!</h2>
      else
        <h2>Coffeescript sucks!</h2>
    }
  </div>