如何有条件的元素,并保持DRY与Facebook React的JSX?

如何在JSX中select性地包含元素? 下面是一个使用横幅的例子,如果它已经被传入,那么我想避免的是在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> ); } 

只是把横幅作为未定义,并不包括在内。

那这个呢。 我们来定义一个简单的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> ); } 

更新:由于我的回答越来越受欢迎,我觉得有义务警告您与此解决scheme有关的最大危险。 正如在另一个答案中指出的那样,无论条件是真还是假, <If />组件中的代码总是被执行。 因此,如果bannernull ,下面的示例将失败(请注意第二行的属性访问):

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

使用时请注意。 我build议阅读其他答案替代(更安全)的方法。

更新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分支很容易,但是通常不那么常见,那么你不能做else if

无论如何,这是可能的,这要归功于JavaScript中的逻辑运算符的工作原理。 逻辑运算符甚至允许这样的小技巧:

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

就我个人而言,我真的认为在http://facebook.github.io/react/tips/if-else-in-JSX.html中显示的三元expression式是符合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> 

If样式组件是危险的,因为无论条件如何,代码块总是被执行 。 例如,如果bannernull ,则会导致空的exception:

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

另一个select是使用内联函数(对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> ); } 

反应问题的另一个选项:

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

你也可以这样写

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

如果你的state.bannernull或者undefined ,则跳过条件的右边。

&& +代码风格+小型组件

这个简单的testing语法+代码风格约定+小集中的组件对我来说是最可读的选项。 你只需要特别注意像false0"" false值。

 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 – 创build一个“如果”组件…一个好主意?

简单,创build一个function。

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

这是我个人始终遵循的模式。 使代码真正干净,易于理解。 如果它变得太大(或在其他地方重新使用),它可以让你将Banner它自己的组件。

实验性的ES7语法使得这一点变得简单。 如果您使用的是Babel,请启用es7.doExpressionsfunction:

 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_expressionions

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

  • 三元操作符

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

  • 逻辑连接

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


但是,那些不工作的 price == 0

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

当“if”分支中有多个元素时,此组件工作:

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

Ps有人认为这个组件对代码阅读不好。 但在我看来,与JavaScript的HTML是更糟的

大多数例子都是有条件地呈现的一行“html”。 这对我来说似乎是可读的,当我有多条线需要有条件地呈现。

 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} {this.props.showContent ? content : otherContent}

但是,如果你只需要显示/隐藏内容,这是更好的,因为布尔值,空值和未定义被忽略

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

还有另一个解决scheme, 如果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> ); } 

我使用更明确的快捷方式:立即调用函数expression式(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})}/> } })()} 

我做了https://www.npmjs.com/package/jsx-control-statements使它更容易一些,基本上它允许你定义;<If>条件作为标签,然后将它们编译成三元ifs,这样代码里面如果条件为真, <If>才会被执行。

我最近做了https://github.com/ajwhite/render-if只有在谓词通过的情况下才能安全地呈现元素。

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

要么

 const ifUniverseIsWorking = renderIf(1 + 1 === 2); //... {ifUniverseIsWorking( <span>Hello!</span> )} 

你可以像下面这样使用三元运算符有条件地包含元素:

 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> } 

您可以使用一个函数并返回组件并保持细化渲染function

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

也许它可以帮助遇到问题的人: React中的所有条件呈现这是一篇关于React中条件呈现的所有不同选项的文章。

关于何时使用哪个条件呈现的关键要点:

** 如果别的

  • 是最基本的条件渲染
  • 初学者友好
  • 使用是否通过返回null来提前退出渲染方法

**三元操作符

  • 通过if-else语句使用它
  • 它比if-else更简洁

**逻辑&&运算符

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

**开关箱

  • 详细
  • 只能用自我调用function来内联
  • 避免它,而不是使用枚举

**枚举

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

**多级/嵌套的条件渲染

  • 为了可读性避免它们
  • 用自己简单的条件渲染将组件分解为更轻量级的组件
  • 使用HOC

** HOC

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

**外部模板组件

  • 避免使用JSX和JavaScript

还有一个非常干净的一行版本… {this.props.product.title || “无题” }

即:

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

我不认为这已经提到。 这就像你自己的答案,但我认为它更简单。 您可以始终从expression式中返回string,并且可以在expression式中嵌套jsx,因此可以轻松地读取内联expression式。

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

我喜欢立即调用函数expression式( IIFE )的明确性,以及if-else over render callbacks函数和ternary 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() { }()) 

这是我使用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 />} 

只有opened才会呈现SomeElement 。 这是因为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 ,所以我觉得这是条件渲染某些元素的好方法。

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

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

只是扩大@Jack Allan的答案与文档的参考。

在这种情况下, 反应基本(Quick Start)文档build议为 null 。 但是,“高级指南”中提到的布尔值,空值和未定义值也被忽略 。