如何使用 Facebook React 的 JSX 拥有条件元素并保持 DRY?
Posted
技术标签:
【中文标题】如何使用 Facebook React 的 JSX 拥有条件元素并保持 DRY?【英文标题】:How to have conditional elements and keep DRY with Facebook React's JSX? 【发布时间】:2014-04-27 15:11:02 【问题描述】:如何在 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>
);
【问题讨论】:
如果您只是没有else
分支怎么办,这行得通吗?我对jsx不熟悉...
很好,这有帮助。另见github.com/facebook/react/issues/690
在 React 中进行条件渲染的详尽选项列表:robinwieruch.de/conditional-rendering-react
【参考方案1】:
将横幅保留为未定义,它不会被包含在内。
【讨论】:
我想不出除了那个答案旁边的垃圾......好像我偶然发现了众神null
是否和undefined
一样好用?规范的那部分是否也是这样工作的,因此将来不太可能中断?【参考方案2】:
这个呢。让我们定义一个简单的帮助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 />
组件内的代码始终执行,无论条件是真还是假。因此,如果banner
是null
,则以下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>
【讨论】:
谢谢。我建议阅读此github.com/facebook/react/issues/690 此链接已发布在此问题下方的 cmets 中,我在发布解决方案后注意到了它。如果你检查它,有些人也会提到这个解决方案,但不推荐它。我个人认为没关系,至少在 OP 的情况下,但确实这种方式并不完美(例如,没有定义 else 分支的好方法)。总之,值得一读。 不确定这是否仍然有效,因为最新版本似乎要求返回值是ReactElement
用另一个元素包裹它,<span>
或 <div>
。
当我尝试使用它来渲染 就个人而言,我真的认为 (JSX In Depth) 中显示的三元表达式是符合 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>
【讨论】:
注意:方括号和组件返回一样,所以你的内容需要用括起来。 @Chiedo 为什么您更喜欢流行的答案?这似乎效果很好。 @moby 我认为流行的答案更具动态性,并产生更清晰的渲染功能。使用这种方法,如果您有多个条件会发生什么?您现在会疯狂地使用这种奇怪的格式进行嵌套,如果两个单独的区域需要基于条件进行相同的更改,您现在必须再次重写条件。虽然只是我的意见! :) 相关页面也挺有用的:facebook.github.io/react/docs/…【参考方案4】:你也可以这样写
this.state.banner && <div>...</div>
如果您的state.banner
是null
或undefined
,则跳过右侧的条件。
【讨论】:
【参考方案5】:If
样式组件很危险,因为无论条件如何,代码块总是执行。例如,如果banner
是null
,这将导致空异常:
//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 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>
);
【讨论】:
在迄今为止的所有解决方案中,内联函数似乎是最优雅和最直接的。有什么需要注意的吗?【参考方案6】:简单,创建一个函数。
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
变得太大(或在其他地方重用),它还允许您将其重构为自己的组件。
【讨论】:
【参考方案7】:&& + 代码风格 + 小组件
这种简单的测试语法 + 代码风格的约定 + 专注的小组件对我来说是最易读的选项。您只需要特别注意 false
、0
或 ""
等虚假值。
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 notation 语法也非常好,当我的 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?
【讨论】:
免费非基本信息:第一个叫short-circuit syntax
@Deerloper 我猜 && 和 & 之间的区别是我们在计算机学校学习的第一件事,但有些人可能不知道,所以给出更多解释也不错:en.wikipedia.org/wiki/Short-circuit_evaluation
没错,但他们将其作为经典条件语句的一部分来教授。我发现很多人对使用短路来渲染 React 组件感到困惑;)【参考方案8】:
实验性的 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
【讨论】:
【参考方案9】:正如答案中已经提到的,JSX 为您提供了两种选择
三元运算符
this.state.price ? <div>this.state.price</div> : null
逻辑连词
this.state.price && <div>this.state.price</div>
但是,这些不适用于 price == 0
。
JSX 将在第一种情况下呈现假分支,在逻辑合取的情况下,不会呈现任何内容。如果属性可能为 0,只需在 JSX 之外使用 if 语句。
【讨论】:
这不是 JSX 问题。这是条件本身,即使在普通的 JS 中也会表现相同。如果您想要任何数字,只需使用typeof(this.state.price) === "number"
作为条件(在任一变体中)。【参考方案10】:
当您在“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>
);
附:有人认为这些组件不利于代码阅读。但在我看来,带有 javascript 的 Html 更糟糕
【讨论】:
就像这里的 If 答案一样,即使没有显示出来,它仍然会执行 false 条件。 这是一个很好的小助手组件,它可以保持代码的简洁和易于使用。它不是总是创建新函数来渲染某些位,而是保持代码干净且易于阅读【参考方案11】:大多数示例都是有条件呈现的一行“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
但如果您只需要显示/隐藏内容,这会更好,因为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>
);
【讨论】:
【参考方案12】:还有另一种解决方案,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>
);
【讨论】:
【参考方案13】:我使用更明确的快捷方式:立即调用函数表达式 (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)/>
)()
【讨论】:
【参考方案14】:也许它可以帮助遇到这个问题的人:All the Conditional Renderings in React 这是一篇关于 React 中条件渲染的所有不同选项的文章。
何时使用哪种条件渲染的关键要点:
** if-else
是最基本的条件渲染 初学者友好 使用 if 通过返回 null 提前退出渲染方法** 三元运算符
在 if-else 语句上使用它 比if-else更简洁** 逻辑 && 运算符
当三元运算的一侧返回 null 时使用它** 开关盒
冗长 只能内联自调用函数 避免它,改用枚举** 枚举
完美映射不同的状态 完美映射多个条件** 多级/嵌套条件渲染
为了可读性而避免使用它们 使用自己的简单条件渲染将组件拆分为更轻量级的组件 使用 HOC** HOC
使用它们来屏蔽条件渲染 组件可以专注于其主要用途** 外部模板组件
避开它们,熟悉 JSX 和 JavaScript【讨论】:
【参考方案15】:我做了https://www.npmjs.com/package/jsx-control-statements 使它更容易一点,基本上它允许您将<If>
条件定义为标签,然后将它们编译成三元ifs,以便<If>
中的代码只有在条件为时才会被执行真的。
【讨论】:
【参考方案16】:还有一个非常干净的单行版本... this.props.product.title || “无标题”
即:
render: function()
return (
<div className="title">
this.props.product.title || "No Title"
</div>
);
【讨论】:
这适用于我上面的示例吗?如果没有banner prop,banner div不应该出现在哪里?【参考方案17】:我最近创建了https://github.com/ajwhite/render-if 以安全地渲染元素只有在谓词通过时。
renderIf(1 + 1 === 2)(
<span>Hello!</span>
)
或
const ifUniverseIsWorking = renderIf(1 + 1 === 2);
//...
ifUniverseIsWorking(
<span>Hello!</span>
)
【讨论】:
【参考方案18】:您可以使用三元运算符有条件地包含元素,如下所示:
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>
【讨论】:
【参考方案19】:您可以使用函数并返回组件并保持渲染函数的细化
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 />
【讨论】:
【参考方案20】:这是我使用 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
,我发现它是有条件地渲染某些元素的好方法。
【讨论】:
【参考方案21】:在 ES6 中,你可以用一个简单的单行代码来做到这一点
const If = (children, show) => show ? children : null
“show”是一个布尔值,你使用这个类
<If show=true> Will show </If>
<If show=false> WON'T show </div> </If>
【讨论】:
不好。它总是会被计算出来的。【参考方案22】:我认为没有人提到这一点。这就像您自己的答案,但我认为它更简单。您总是可以从表达式中返回字符串,并且可以将 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>
【讨论】:
【参考方案23】:我喜欢立即调用函数表达式 (IIFE
) 和 if-else
优于 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()
()
需要包裹在括号内
(function()
())
【讨论】:
【参考方案24】:还有一种技术使用 render props 来条件渲染组件。这样做的好处是在满足条件之前渲染不会进行评估,从而无需担心 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>
)
/>
)
【讨论】:
【参考方案25】:如果必须仅在满足传递的条件时渲染某些内容,您可以使用语法:
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 中进行条件渲染的方法!
【讨论】:
【参考方案26】:我只是在 React with TypeScript 中使用以下 sn-p
export default function ReactIf(props: condition: boolean, children: React.ReactNode )
return props.condition ? <React.Fragment>props.children</React.Fragment> : <React.Fragment/>;
【讨论】:
【参考方案27】:只是添加另一个选项 - 如果你喜欢/容忍咖啡脚本,你可以使用咖啡反应来编写你的 JSX,在这种情况下 if/else 语句是可用的,因为它们是咖啡脚本中的表达式而不是语句:
render: ->
<div className="container">
if something
<h2>Coffeescript is magic!</h2>
else
<h2>Coffeescript sucks!</h2>
</div>
【讨论】:
【参考方案28】:只是通过引用文档来扩展@Jack Allan 的答案。
React basic (Quick Start) documentation suggests null
在这种情况下。
但是,Booleans, Null, and Undefined Are Ignored 也一样,在高级指南中提到。
【讨论】:
已更正以澄清 -- false、null、undefined 和 true 也可以忽略 -- facebook.github.io/react/docs/…。虽然,在快速入门中,他们更喜欢建议 null。以上是关于如何使用 Facebook React 的 JSX 拥有条件元素并保持 DRY?的主要内容,如果未能解决你的问题,请参考以下文章
[React 基础系列] 什么是 JSX,以及如何使用 JSX
让 Facebook 的 react.js 库 JSX 语法与 jslint 完美搭配?
前端库-React框架:「01] 创建一个简单的 JSX 元素