在React应用程序中实现条件渲染的7种方法
介绍
您可以使用 React 构建动态且高度交互的单页应用程序 (SPA)。 允许这样做的一个功能是条件渲染。
条件渲染是一个术语,用于描述在条件为真或假时渲染不同用户界面 (UI) 标记的能力。 在 React 中,它允许我们根据条件渲染不同的元素或组件。 这个概念经常应用在以下场景中:
- 从 API 渲染外部数据。
- 显示或隐藏元素。
- 切换应用程序功能。
- 实施权限级别。
- 处理身份验证和授权。
在本文中,您将研究在 React 应用程序中实现条件渲染的七种方法。
先决条件
要完成本教程,您需要:
- 了解 JavaScript 变量和函数。 您可以参考 如何在 JavaScript 系列中编写代码以了解更多信息。
- 了解 React 组件的导入、导出和渲染。 您可以查看我们的 如何在 React.js 系列中编码。
- Node.js 安装在本地,您可以按照【X57X】如何安装Node.js 并创建本地开发环境【X126X】进行。
本教程已使用 Node v15.6.0、npm v7.4.0 和 react v17.0.1 进行了验证。
设置示例项目
考虑一个需要用户登录的应用程序。 如果用户已注销,它将显示一个 Login 按钮。 如果用户已登录,将显示 Logout 按钮。
首先使用 create-react-app 生成 React App:
npx create-react-app react-conditional-rendering-example
切换到新的项目目录:
cd react-conditional-rendering-example
接下来,在代码编辑器中打开 App.js 文件。 并将内容替换为以下代码行:
src/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 文件。 并将内容替换为以下代码行:
src/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 以在您完成本教程时回滚更改。
此时,您将拥有一个显示 Login 和 Logout 按钮的 React 应用程序。 您的目标是只显示其中一个按钮。 让我们看一下实现此目的的条件渲染方法。
1. 使用 if…else 语句
当条件满足时,if…else 语句将执行包含在 if 块中的动作。 否则,它将执行包含在 else 块中的动作。
在 JSX 中,您可以使用带有标记的 JavaScript 代码在应用程序中呈现动态值。 JSX 使用花括号({ 和 })来表示需要在渲染之前解释的表达式。 然而,需要注意的是,在这种大括号内可以做的事情是有限制的。
让我们考虑您是否尝试在 render() 方法中使用 if…else 语句:
警告: 这是一个无法正常工作的代码示例。 它作为 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() 方法并进行以下突出显示的代码更改:
src/App.js
// ...
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 浏览器中打开您的应用程序。 以前,会显示 Login 和 Logout 按钮。 现在,isLoggedIn 状态为 true 并且条件逻辑导致仅显示 Logout 按钮。
现在,让我们考虑您是否尝试在 render() 方法中使用多个 return 来代替:
警告: 这是应避免的性能不佳代码的示例。
// ...
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 文件:
src/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 属性传递的状态值返回各种元素或组件。
接下来,重新访问 App.js 并修改它以使用新组件:
src/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 语句:
src/AuthButton.js
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 内呈现变量。
应用程序可以这样重写:
src/App.js
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 语句的快捷方式。
应用程序可以这样重写:
src/App.js
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;
如果这种方法使组件变得臃肿、笨重或可读性降低,您可以将条件封装在功能组件中:
src/AuthButton.js
import React from "react";
const AuthButton = props => {
let { isLoggedIn } = props;
return isLoggedIn ? <button>Logout</button> : <button>Login</button>;
};
export default AuthButton;
三元方法对于简单的 if…else 评估很有用。 对于复杂的比较和组件,它可能会随着项目的增长而影响可读性。
5. 使用逻辑 &&(短路评估)
短路评估是一种用于确保在评估表达式中的操作数期间没有副作用的技术。 逻辑 && 可帮助您指定仅应在一个条件下执行操作,否则将被完全忽略。
应用程序可以这样重写:
src/App.js
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,此代码将显示 Logout 按钮,否则将不显示任何内容。
现在,让我们考虑对 Login 按钮进行第二次短路评估:
警告: 这是应避免的性能不佳代码的示例。
{isLoggedIn && <button>Logout</button>}
{!isLoggedIn && <button>Login</button>}
此代码将根据 isLoggedIn 的值呈现右键。 但是,不建议这样做,因为有更好、更清洁的方法可以达到相同的效果。 随着您的应用程序的增长,过度使用短路评估可能会变得繁琐且不直观。
6. 使用立即调用函数表达式 (IIFE)
前面的部分提到 JSX 的限制使它无法执行所有类型的 JavaScript 代码。 使用立即调用函数表达式 (IFFE) 可以绕过这些限制。 IFFEs 是一个 JavaScript 函数,一旦定义就会运行:
(function () {
// statements
})();
使用这种技术,您可以直接在 JSX 中编写条件逻辑,但将其包装在一个匿名函数中,该函数在评估该代码时立即被调用。
应用程序可以这样重写:
src/App.js
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>;
}
})()}
您可以从 MDN 了解有关 IIFE 的更多信息。
7. 使用增强的 JSX 库
某些库公开了扩展 JSX 的功能,从而可以直接使用 JSX 实现条件渲染。 此类库之一是 JSX 控制语句 。 它是一个 Babel 插件,可在转译期间将类似组件的控制语句转换为对应的 JavaScript。
安装 babel-plugin-jsx-control-statements 包并修改你的 Babel 配置后,应用程序可以这样重写:
src/App.js
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 应用程序中实现条件渲染的七种方法。 每种方法都有自己的优势,选择使用哪种方法主要取决于用例。
有关更多信息,请参阅 条件渲染 的文档。
继续学习 高阶组件 和 使用 HOC 进行条件渲染 。