介绍
您可以构建动态且与 React 高度交互的单页应用程序 (SPA)。允许这样做的一个功能是条件渲染。
条件呈现是一个术语,用于描述在条件为真或为假时呈现不同用户界面 (UI) 标记的能力。在 React 中,它允许我们根据条件渲染不同的元素或组件。这个概念经常应用于以下场景:
- 从 API 呈现外部数据。
- 显示或隐藏元素。
- 切换应用程序功能。
- 实施权限级别。
- 处理身份验证和授权。
在本文中,您将研究在 React 应用程序中实现条件渲染的七种方法。
先决条件
要完成本教程,您需要:
- 了解 JavaScript 变量和函数。您可以查阅如何在 JavaScript 中编码系列以了解更多信息。
- 了解导入、导出和渲染 React 组件。您可以查看我们的“如何在 React.js 中编码”系列。
- Node.js 安装在本地,您可以按照如何安装 Node.js 和创建本地开发环境来完成。
本教程已通过 Node v15.6.0、npm v7.4.0 和react
v17.0.1 验证。
设置示例项目
考虑一个需要用户登录的应用程序。如果用户已注销,它将显示一个登录按钮。如果用户已登录,它将显示一个注销按钮。
从使用create-react-app
生成 React App 开始:
- npx create-react-app react-conditional-rendering-example
切换到新的项目目录:
- cd react-conditional-rendering-example
接下来,App.js
在您的代码编辑器中打开该文件。并用以下代码行替换内容:
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<button>Login</button>
<button>Logout</button>
</div>
);
}
}
export default App;
接下来,App.css
在您的代码编辑器中打开该文件。并用以下代码行替换内容:
body {
padding: 1em;
}
h1 {
font-size: 3em;
font-weight: 500;
text-align: center;
margin-bottom: 1em;
margin-right: 1em;
padding: 0;
}
button {
appearance: none;
background-color: #246bec;
border: 1px solid #246bec;
border-radius: 0;
box-sizing: border-box;
color: #ffffff;
display: block;
font-size: 2em;
font-weight: 500;
margin-bottom: 1em;
margin-top: 1em;
padding: .5em;
width: 100%;
transition: border-color, background-color 300ms ease-in-out;
}
button:focus {
border-color: #00006D;
}
button:hover {
background-color: #0B52D3;
}
button:active {
background-color: #00006D;
}
然后,从终端窗口运行应用程序:
- npm start
并在浏览器中与应用程序交互:
每种条件渲染方法都将建立在此代码之上。您可能希望git commit
在此时创建一个以在您完成本教程时回滚更改。
此时,您将拥有一个显示登录和注销按钮的 React 应用程序。您的目标是只显示这些按钮之一。让我们看看实现这一点的条件渲染方法。
1. 使用if…else
语句
一个if…else
语句将执行包含在行动if
当条件满足块。否则,它将执行else
块中包含的操作。
在 JSX 中,您可以使用带有标记的 JavaScript 代码来呈现应用程序中的动态值。JSX 使用大括号({
和}
)来表示需要在渲染之前解释的表达式。然而,需要注意的是,在这种大括号内可以做的事情是有限的。
让我们考虑一下您是否要尝试if…else
在render()
方法中使用语句:
警告:这是一个无法正常工作的代码示例。它是作为render()
方法中解释限制的一个例子提出的。
// ...
class App extends Component {
// ...
render() {
let {isLoggedIn} = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{
if(isLoggedIn){
return <button>Logout</button>
} else{
return <button>Login</button>
}
}
</div>
);
}
}
// ...
此代码会产生Unexpected token
错误。逻辑将需要移到render()
方法之外。
App.js
在代码编辑器中打开文件,向下滚动到该render()
方法并进行以下突出显示的代码更改:
// ...
class App extends Component {
// ...
render() {
let {isLoggedIn} = this.state;
const renderAuthButton = () => {
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
}
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{renderAuthButton()}
</div>
);
}
}
// ...
这是创建提取函数的过程。此代码将 JSX 中的逻辑提取到一个函数中renderAuthButton
。该函数在 JSX 花括号内执行。
在 Web 浏览器中打开您的应用程序。以前,会显示登录和注销按钮。现在,isLoggedIn
状态true
和条件逻辑导致仅显示注销按钮。
现在,让我们考虑一下是否要尝试return
在render()
方法中使用多个s :
警告:这是应该避免的低性能代码示例。
// ...
class App extends Component {
// ...
render() {
let {isLoggedIn} = this.state;
if (isLoggedIn) {
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<button>Logout</button>
</div>
);
} else {
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<button>Login</button>
</div>
);
}
}
}
// ...
上面的代码片段将实现相同的结果,但由于不断重新渲染不变的组件而导致组件不必要的膨胀,同时引入了性能问题。
最佳实践是使组件尽可能简单,以避免重复渲染兄弟组件或父组件。
在您的代码编辑器中,创建一个新AuthButton.js
文件:
import React from "react";
const AuthButton = props => {
let { isLoggedIn } = props;
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
};
export default AuthButton;
AuthButton
根据通过isLoggedIn
props传递的 state 的值返回各种元素或组件。
接下来,重新访问App.js
并修改它以使用新组件:
import React, { Component } from "react";
import './App.css';
import AuthButton from "./AuthButton";
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<AuthButton isLoggedIn={isLoggedIn} />
</div>
);
}
}
export default App;
这是创建提取的功能组件的过程。此代码产生与该renderAuthButton()
方法相同的结果。但具有将更改移动到单独组件的优势。
2. 使用switch
语句
如前所述,您可以使用if…else
语句根据设置的条件有条件地从组件返回不同的标记。使用可以switch
为各种条件指定标记的语句也可以实现相同的目的。
修改AuthButton
组件并用if…else
语句替换switch
语句:
import React from "react";
const AuthButton = props => {
let { isLoggedIn } = props;
switch (isLoggedIn) {
case true:
return <button>Logout</button>;
break;
case false:
return <button>Login</button>;
break;
default:
return null;
}
};
export default AuthButton;
请注意此代码如何根据 的值返回各种按钮isLoggedIn
。
注意:switch
当有两个以上的可能值或结果时,应用语句方法会更实用。
此外,null
从组件返回将导致它隐藏自身(不显示任何内容)。这是切换组件可见性的好方法。
3. 使用元素变量
元素变量类似于将条件渲染提取到函数中的方法。元素变量是保存 JSX 元素的变量。您可以在 JSX 之外有条件地将元素或组件分配给这些变量,并且仅在 JSX 内呈现变量。
应用程序可以这样重写:
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
let AuthButton;
if (isLoggedIn) {
AuthButton = <button>Logout</button>;
} else {
AuthButton = <button>Login</button>;
}
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{AuthButton}
</div>
);
}
}
export default App;
注意这段代码是如何有条件地分配值 – 组件 –AuthButton
然后它可以在 JSX 中被引用。
4. 使用三元运算符
条件(三元)运算符是唯一一个接受三个操作数的 JavaScript 运算符。此运算符经常用作if
语句的快捷方式。
应用程序可以这样重写:
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{isLoggedIn ? <button>Logout</button> : <button>Login</button>}
</div>
);
}
}
export default App;
在这种方法使组件膨胀、笨重或可读性较差的情况下,您可以将条件封装在功能组件中:
import React from "react";
const AuthButton = props => {
let { isLoggedIn } = props;
return isLoggedIn ? <button>Logout</button> : <button>Login</button>;
};
export default AuthButton;
三元方法对于简单的if…else
评估很有用。对于复杂的比较和组件,随着项目的增长,它可能会影响可读性。
5. 使用逻辑&&
(短路评估)
短路评估是一种用于确保在评估表达式中的操作数期间没有副作用的技术。逻辑&&
可帮助您指定仅应在一种情况下执行操作,否则将被完全忽略。
应用程序可以这样重写:
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{isLoggedIn && <button>Logout</button>}
</div>
);
}
}
export default App;
如果是,此代码将显示注销按钮,否则将不显示任何内容。isLoggedIn
true
现在,让我们考虑对登录按钮使用第二个短路评估:
警告:这是应该避免的低性能代码示例。
{isLoggedIn && <button>Logout</button>}
{!isLoggedIn && <button>Login</button>}
此代码将根据 的值呈现右侧按钮isLoggedIn
。但是,不建议这样做,因为有更好、更简洁的方法来实现相同的效果。随着应用程序的增长,这种对短路评估的过度使用可能会变得繁琐和不直观。
6. 使用立即调用函数表达式 (IIFE)
前面的部分提到 JSX 的限制使其无法执行所有类型的 JavaScript 代码。使用立即调用函数表达式 (IFFE) 可以绕过这些限制。IFFEs 是一个 JavaScript 函数,它在定义后立即运行:
(function () {
// statements
})();
使用这种技术,您可以直接在 JSX 中编写条件逻辑,但包装在匿名函数中,该函数在评估该代码时立即调用。
应用程序可以这样重写:
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
{(function() {
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
})()}
</div>
);
}
}
export default App;
这也可以使用箭头函数以更简洁的方式编写:
{(() => {
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
})()}
7. 使用增强的 JSX 库
某些库公开了扩展 JSX 的功能,从而可以直接使用 JSX 实现条件渲染。这样的库之一是JSX Control Statements。它是一个Babel插件,可在转换过程中将类似组件的控制语句转换为它们的 JavaScript 对应语句。
安装babel-plugin-jsx-control-statements
包并修改 Babel 配置后,应用程序可以像这样重写:
import React, { Component } from "react";
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true
};
}
render() {
let { isLoggedIn } = this.state;
return (
<div className="App">
<h1>
This is a Demo showing several ways to implement Conditional Rendering in React.
</h1>
<Choose>
<When condition={isLoggedIn}>
<button>Logout</button>;
</When>
<When condition={!isLoggedIn}>
<button>Login</button>;
</When>
</Choose>
</div>
);
}
}
export default App;
但是,不建议使用这种方法,因为您编写的代码最终会转换为常规 JavaScript 条件。只写 JavaScript 可能总是比在如此琐碎的事情上添加额外的依赖要好。
选择条件渲染方法
作为一般规则,最好确保在实现条件渲染时:
- 请勿随意改变组件位置,以免不必要的拆装组件。
- 仅更改与条件呈现相关的标记。
- 不要在
render
方法中不必要地膨胀你的组件,因为这会导致组件延迟渲染。
有关更多信息,请参阅Cole Williams撰写的有关 React 中高性能条件的文章。
需要考虑的事项包括:
- 要有条件地呈现的标记的大小
- 可能结果的数量
- 哪个更直观和可读
通常,请记住以下建议:
- 对于只有一种预期结果的情况,“短路评估”可能最适用。
- 对于有两个预期结果的情况,
if…else
语句、元素变量、三元运算符或“立即调用的函数表达式”可能最适用。 - 对于有两个以上结果的情况,
switch
语句、提取的功能或提取的功能组件可能最适用。
请记住,这些是建议而不是规则。您项目的需求和惯例可能要求您采用不遵循这些建议的方法。
结论
在本文中,您研究了在 React 应用程序中实现条件渲染的七种方法。每种方法都有自己的优势,选择使用哪种方法主要取决于用例。
有关更多信息,请参阅Conditional Rendering的文档。
继续学习高阶组件和使用 HOC 的条件渲染。