如何有条件元素和保持干燥与Facebook React's 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>
);
}
144466 次浏览

只是留下旗帜为未定义,它不包括在内。

这个呢?让我们定义一个简单的帮助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的情况下,下面的例子将失败(注意第二行中的属性访问):

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

你使用它的时候一定要小心。我建议你阅读其他的(更安全的)方法。

回头看,这种方法不仅危险,而且极其繁琐。这是一个典型的例子,当一个开发人员(我)试图将他知道的模式和方法从一个领域转移到另一个领域,但它实际上不起作用(在这种情况下是其他模板语言)。

如果你需要一个条件元素,可以这样做:

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中的逻辑运算符的工作方式。逻辑运算符甚至允许这样的小技巧:

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

当你在"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>
);
}

附注:有些人认为这些组件不适合代码阅读。但在我看来,Html和javascript更糟糕

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

react 问题的另一个选项:

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

我创建https://www.npmjs.com/package/jsx-control-statements是为了让它更简单一点,基本上它允许你将<If>条件定义为标记,然后将它们编译为三元if,这样<If>中的代码只有在条件为真时才会执行。

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

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

就我个人而言,我真的认为(JSX深入)中显示的三元表达式是符合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>

,,+代码风格+小组件

对我来说,这种简单的测试语法+代码风格的约定+小型集中组件是最易读的选项。你只需要特别注意像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 do符号语法也非常好,当我的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 -创建一个“如果”;元件…好主意?

实验性的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

还有一个非常简洁的单行版本……{this.props.product.title || "No Title"}

即:

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

还有另一个解决方案,React的if组件:

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

我最近创建了https://github.com/ajwhite/render-if,以安全地呈现元素仅当谓词传递时

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

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


//...


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

你也可以这样写

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

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

大多数例子都只有一行“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>
);
}

第一个例子很好,因为我们可以有条件地呈现一些其他内容,如{this.props.showContent ? content : otherContent}

但如果你只是需要显示/隐藏内容,这是更好的,因为忽略布尔值、Null和Undefined

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

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

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

我想这一点没有被提及。这就像你自己的答案,但我认为它更简单。您总是可以从表达式中返回字符串,并且可以在表达式中嵌套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>
);
}

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

你可以使用一个函数并返回组件,同时保持渲染函数的精简

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

很简单,创建一个函数。

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变得太大(或在其他地方重用),它允许你将Banner重构为自己的组件。

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

  • < p >三元操作符

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

  • < p >逻辑连词

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


然而,这些并不适用 price == 0

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

我使用一个更显式的快捷方式:立即调用函数表达式(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})}/>
}
})()}

我喜欢立即调用函数表达式(IIFE)和if-else的显式性,而不是render 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() {


}()

需要用括号来包装

(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,我发现这是有条件呈现某些元素的好方法。

React中所有的条件渲染这是一篇关于React中条件渲染的所有不同选项的文章。

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

* * if - else

  • 最基本的是条件渲染吗
  • 初学者友好
  • 使用if可以通过返回null提早退出渲染方法

**三元运算符

  • 在if-else语句外使用它
  • 它比if-else更简洁

**逻辑&&操作符

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

**开关箱

  • 详细的
  • 只能内联自调用函数
  • 避免使用枚举

* *枚举

  • 完美地映射不同的州
  • 完美地映射不止一个条件

**多级/嵌套条件渲染

  • 为了可读性,避免使用它们
  • 将组件拆分为具有自己的简单条件呈现的更轻量级的组件
  • 使用的

* *的

  • 使用它们来屏蔽条件呈现
  • 组件可以专注于它们的主要用途

**外部模板组件

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

只是为了扩展@Jack Allan的回答,引用文档。

React基本(快速入门)文档建议 null在这种情况下。 然而,忽略布尔值、Null和Undefined也一样,在高级指南中提到过

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

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

在ES6中,你可以用简单的一行程序来实现

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

"show"是一个布尔值,你可以通过

<If show={true}> Will show </If>
<If show={false}> WON'T show </div> </If>

当必须只渲染某些东西,如果传递的条件是完全满足的,你可以使用语法:

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

当然,还有其他有效的方法来做到这一点,这完全取决于偏好和场合。如果你感兴趣,你可以在这篇文章中学习更多如何在React中进行条件渲染的方法!

我只是在React with TypeScript中使用了下面的代码片段

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