在 React 应用程序中实现条件仁登的 7 种方法

简介

您可以使用Reaction构建动态且高度交互的单页应用程序(SPA)。支持此功能的一个功能是条件呈现。

条件呈现是一个术语,用于描述在条件为真或假时呈现不同用户界面(UI)标记的能力。在React中,它允许我们根据条件渲染不同的元素或组件。这个概念通常应用于以下场景:

  • 从API渲染外部数据。
  • 显示或隐藏元素。
  • 切换应用程序功能。
  • 实现权限级别。
  • 处理身份验证和授权。

在本文中,您将研究在Reaction应用程序中实现条件呈现的七种方法。

预约

要完成本教程,您需要:

本教程已使用Node v15.6.0、npm v7.4.0和react v17.0.1进行了验证。

设置示例工程

考虑一个需要用户登录的应用程序。如果用户已注销,则会显示登录 按钮。如果用户已登录,则会显示** 注销** 按钮。

首先使用create-react-app生成一个Reaction应用程序:

1npx create-react-app react-conditional-rendering-example

切换到新的项目目录:

1cd react-conditional-rendering-example

接下来,在代码编辑器中打开App.js文件。并将内容替换为以下代码行:

 1[label src/App.js]
 2import React, { Component } from "react";
 3import './App.css';
 4
 5class App extends Component {
 6  constructor(props) {
 7    super(props);
 8    this.state = {
 9      isLoggedIn: true
10    };
11  }
12
13  render() {
14    return (
15      <div className="App">
16        <h1>
17          This is a Demo showing several ways to implement Conditional Rendering in React.
18        </h1>
19        <button>Login</button>
20        <button>Logout</button>
21      </div>
22    );
23  }
24}
25
26export default App;

接下来,在代码编辑器中打开App.css文件。并将内容替换为以下代码行:

 1[label src/App.css]
 2body {
 3  padding: 1em;
 4}
 5
 6h1 {
 7  font-size: 3em;
 8  font-weight: 500;
 9  text-align: center;
10  margin-bottom: 1em;
11  margin-right: 1em;
12  padding: 0;
13}
14
15button {
16  appearance: none;
17  background-color: #246bec;
18  border: 1px solid #246bec;
19  border-radius: 0;
20  box-sizing: border-box;
21  color: #ffffff;
22  display: block;
23  font-size: 2em;
24  font-weight: 500;
25  margin-bottom: 1em;
26  margin-top: 1em;
27  padding: .5em;
28  width: 100%;
29  transition: border-color, background-color 300ms ease-in-out;
30}
31
32button:focus {
33  border-color: #00006D;
34}
35
36button:hover {
37  background-color: #0B52D3;
38}
39
40button:active {
41  background-color: #00006D;
42}

然后,从您的终端窗口运行该应用程序:

1npm start

并在您的浏览器中与应用程序交互:

带有登录和注销按钮的React应用程序屏幕截图

每种条件呈现方法都将基于此代码构建。在这一点上,你可能希望创建一个git commit,以便在本教程的过程中回滚更改。

此时,您将拥有一个Reaction应用程序,其中显示一个Login 和一个** Logout** 按钮。您的目标是只显示其中一个按钮。让我们来看看实现这一点的条件呈现方法。

1.使用if...else语句

一个if…当满足条件时,其他语句将执行if块中包含的操作。否则,它将执行thers块中包含的操作。

在JSX中,您可以使用带有标记的JavaScript代码在应用程序中呈现动态值。JSX使用花括号({})表示渲染前需要解释的表达式。然而,需要注意的是,在这样的支撑下可以做的事情是有限的。

让我们来考虑一下,如果您尝试使用if…render()方法中的其他语句:

<$>[警告] 警告: 这是一个无法正常工作的代码示例。它是作为render()方法中解释限制的一个例子。 <$>

 1// ...
 2
 3class App extends Component {
 4  // ...
 5
 6  render() {
 7    let {isLoggedIn} = this.state;
 8
 9    return (
10      <div className="App">
11        <h1>
12          This is a Demo showing several ways to implement Conditional Rendering in React.
13        </h1>
14        {
15          if(isLoggedIn){
16            return <button>Logout</button>
17          } else{
18            return <button>Login</button>
19          }
20        }
21      </div>
22    );
23  }
24}
25
26// ...

此代码将产生一个‘意外令牌’错误。需要将该逻辑移到render()方法之外。

在代码编辑器中打开App.js文件,向下滚动到render()方法,并进行以下突出显示的代码更改:

 1[label src/App.js]
 2// ...
 3
 4class App extends Component {
 5  // ...
 6
 7  render() {
 8    let {isLoggedIn} = this.state;
 9
10    const renderAuthButton = () => {
11      if (isLoggedIn) {
12        return <button>Logout</button>;
13      } else {
14        return <button>Login</button>;
15      }
16    }
17
18    return (
19      <div className="App">
20        <h1>
21          This is a Demo showing several ways to implement Conditional Rendering in React.
22        </h1>
23        {renderAuthButton()}
24      </div>
25    );
26  }
27}
28
29// ...

这是创建提取函数的过程。此代码将JSX中的逻辑提取到函数renderAuthButton中。并且该函数在JSX大括号内执行。

在Web浏览器中打开您的应用程序。在此之前,会显示登录 和** 注销** 按钮。现在,isLoggedIn状态为true,条件逻辑导致只显示** 注销** 按钮。

现在,让我们考虑一下,如果您尝试在render()方法中使用多个`reurn:

<$>[警告] 警告: 这是一个应该避免的性能较差的代码示例。 <$>

 1// ...
 2
 3class App extends Component {
 4  // ...
 5
 6  render() {
 7    let {isLoggedIn} = this.state;
 8
 9    if (isLoggedIn) {
10      return (
11        <div className="App">
12          <h1>
13            This is a Demo showing several ways to implement Conditional Rendering in React.
14          </h1>
15          <button>Logout</button>
16        </div>    
17      );
18    } else {
19      return (
20        <div className="App">
21          <h1>
22            This is a Demo showing several ways to implement Conditional Rendering in React.
23          </h1>
24          <button>Login</button>
25        </div>    
26      );
27    }
28  }
29}
30
31// ...

上面的代码片断将达到相同的结果,但会不必要地使组件膨胀,同时由于不断重新呈现不变的组件而导致性能问题。

最佳实践是使组件尽可能简单,以避免对同级或父组件进行浪费的重新呈现。

在代码编辑器中,新建一个AuthButton.js文件:

 1[label src/AuthButton.js]
 2import React from "react";
 3
 4const AuthButton = props => {
 5  let { isLoggedIn } = props;
 6
 7  if (isLoggedIn) {
 8    return <button>Logout</button>;
 9  } else {
10    return <button>Login</button>;
11  }
12};
13
14export default AuthButton;

AuthButton根据通过isLoggedIn道具向下传递的状态值返回各种元素或组件。

接下来,重新访问App.js并将其修改为使用新组件:

 1[label src/App.js]
 2import React, { Component } from "react";
 3import './App.css';
 4import AuthButton from "./AuthButton";
 5
 6class App extends Component {
 7  constructor(props) {
 8    super(props);
 9    this.state = {
10      isLoggedIn: true
11    };
12  }
13
14  render() {
15    return (
16      <div className="App">
17        <h1>
18          This is a Demo showing several ways to implement Conditional Rendering in React.
19        </h1>
20        <AuthButton isLoggedIn={isLoggedIn} />
21      </div>
22    );
23  }
24}
25
26export default App;

这是创建提取的功能组件的过程。此代码产生与renderAuthButton()方法相同的结果。但具有将更改移动到单独组件的优点。

2.使用Switch语句

如前所述,您可以使用if…根据设置的条件从组件有条件地返回不同的标记Else‘语句。这可以通过Switch`语句实现,在该语句中,您可以为各种条件指定标记。

修改AuthButton组件并替换if…带有Switch语句的其他语句:

 1[label src/AuthButton.js]
 2import React from "react";
 3
 4const AuthButton = props => {
 5  let { isLoggedIn } = props;
 6
 7  switch (isLoggedIn) {
 8    case true:
 9      return <button>Logout</button>;
10      break;
11    case false:
12      return <button>Login</button>;
13      break;
14    default:
15      return null;
16  }
17};
18
19export default AuthButton;

注意这段代码是如何根据isLoggedIn的值返回各种按钮的。

<$>[备注] 注意: 当存在两个以上可能的值或结果时,使用Switch语句方法会更实用。 <$>

此外,从组件返回null会导致其隐藏自身(不显示任何内容)。这是切换零部件可见性的好方法。

3.使用元素变量

元素变量类似于将条件呈现提取到函数中的方法。元素变量是保存JSX元素的变量。您可以有条件地将元素或组件分配给JSX外部的这些变量,并且只在JSX内呈现该变量。

应用程序可以按如下方式重写:

 1[label src/App.js]
 2import React, { Component } from "react";
 3import './App.css';
 4
 5class App extends Component {
 6  constructor(props) {
 7    super(props);
 8    this.state = {
 9      isLoggedIn: true
10    };
11  }
12
13  render() {
14    let { isLoggedIn } = this.state;
15    let AuthButton;
16
17    if (isLoggedIn) {
18      AuthButton = <button>Logout</button>;
19    } else {
20      AuthButton = <button>Login</button>;
21    }
22
23    return (
24      <div className="App">
25        <h1>
26          This is a Demo showing several ways to implement Conditional Rendering in React.
27        </h1>
28        {AuthButton}
29      </div>
30    );
31  }
32}
33
34export default App;

注意这段代码如何有条件地将值-组件-赋值给AuthButton,然后可以在稍后的JSX中引用它。

4.使用三进制运算符

条件(三元)运算符是唯一接受三个操作数的JavaScript运算符。此运算符经常用作if语句的快捷方式。

应用程序可以按如下方式重写:

 1[label src/App.js]
 2import React, { Component } from "react";
 3import './App.css';
 4
 5class App extends Component {
 6  constructor(props) {
 7    super(props);
 8    this.state = {
 9      isLoggedIn: true
10    };
11  }
12
13  render() {
14    let { isLoggedIn } = this.state;
15
16    return (
17      <div className="App">
18        <h1>
19          This is a Demo showing several ways to implement Conditional Rendering in React.
20        </h1>
21        {isLoggedIn ? <button>Logout</button> : <button>Login</button>}
22      </div>
23    );
24  }
25}
26
27export default App;

在这种方法使组件变得臃肿、笨重或可读性较差的情况下,您可以将条件封装在功能组件中:

 1[label src/AuthButton.js]
 2import React from "react";
 3
 4const AuthButton = props => {
 5  let { isLoggedIn } = props;
 6
 7  return isLoggedIn ? <button>Logout</button> : <button>Login</button>;
 8};
 9
10export default AuthButton;

三元方法对于简单的if...else计算很有用。对于复杂的比较和组件,随着项目的增长,它可能会影响可读性。

5.使用逻辑&&(短路评估)

短路求值是一种用于确保在计算表达式中的操作数期间没有副作用的技术。逻辑&&帮助您指定一个操作只能在一个条件下执行,否则将被完全忽略。

应用程序可以按如下方式重写:

 1[label src/App.js]
 2import React, { Component } from "react";
 3import './App.css';
 4
 5class App extends Component {
 6  constructor(props) {
 7    super(props);
 8    this.state = {
 9      isLoggedIn: true
10    };
11  }
12
13  render() {
14    let { isLoggedIn } = this.state;
15
16    return (
17      <div className="App">
18        <h1>
19          This is a Demo showing several ways to implement Conditional Rendering in React.
20        </h1>
21        {isLoggedIn && <button>Logout</button>}
22      </div>
23    );
24  }
25}
26
27export default App;

如果isLoggedIntrue,则此代码将显示注销 按钮,否则将不显示任何内容。

现在,让我们考虑对 Login 按钮使用第二个短路评估:

<$>[警告] 警告: 这是一个应该避免的性能较差的代码示例。 <$>

1{isLoggedIn && <button>Logout</button>}
2{!isLoggedIn && <button>Login</button>}

这段代码将根据isLoggedIn的值呈现右按钮。但是,这并不推荐,因为有更好,更干净的方法可以达到同样的效果。随着应用程序的增长,这种过度使用短路评估可能会变得繁琐和不直观。

6.使用立即调用的函数表达式(IIFE)

前面几节提到,JSX的限制使其无法执行所有类型的JavaScript代码。使用立即调用的函数表达式(IFFE)可以绕过这些限制。IFFES是一个JavaScript函数,一旦定义就会运行:

1(function () {
2  // statements
3})();

使用这种技术,您可以直接在JSX中编写条件逻辑,但可以包装在一个匿名函数中,该函数在代码求值时立即被调用。

应用程序可以按如下方式重写:

 1[label src/App.js]
 2import React, { Component } from "react";
 3import './App.css';
 4
 5class App extends Component {
 6  constructor(props) {
 7    super(props);
 8    this.state = {
 9      isLoggedIn: true
10    };
11  }
12
13  render() {
14    let { isLoggedIn } = this.state;
15
16    return (
17      <div className="App">
18        <h1>
19          This is a Demo showing several ways to implement Conditional Rendering in React.
20        </h1>
21        {(function() {
22          if (isLoggedIn) {
23            return <button>Logout</button>;
24          } else {
25            return <button>Login</button>;
26          }
27        })()}
28      </div>
29    );
30  }
31}
32
33export default App;

这也可以使用箭头函数以稍微更简洁的方式编写:

1{(() => {
2  if (isLoggedIn) {
3    return <button>Logout</button>;
4  } else {
5    return <button>Login</button>;
6  }
7})()}

你可能会从MDN](https://developer.mozilla.org/en-US/docs/Glossary/IIFE).了解更多关于[LIFE

7.使用增强型JSX库

某些库公开了扩展JSX的功能,使直接使用JSX实现条件呈现成为可能。其中一个库是JSX Control Statements.它是一个Babel插件,用于在转换过程中将类似组件的控制语句转换为与之对应的脚本。

安装babel-plugin-jsx-control-statements包并修改您的babel配置后,应用程序可以重写如下:

 1[label src/App.js]
 2import React, { Component } from "react";
 3import './App.css';
 4
 5class App extends Component {
 6  constructor(props) {
 7    super(props);
 8    this.state = {
 9      isLoggedIn: true
10    };
11  }
12
13  render() {
14    let { isLoggedIn } = this.state;
15
16    return (
17      <div className="App">
18        <h1>
19          This is a Demo showing several ways to implement Conditional Rendering in React.
20        </h1>
21        <Choose>
22          <When condition={isLoggedIn}>
23             <button>Logout</button>;
24          </When>
25          <When condition={!isLoggedIn}>
26             <button>Login</button>;
27          </When>
28        </Choose>
29      </div>
30    );
31  }
32}
33
34export default App;

但是,不推荐使用这种方法,因为您编写的代码最终会转换为常规的JavaScript条件。仅仅编写JavaScript可能总是比在如此琐碎的事情上添加额外的依赖项要好。

选择条件渲染方式

作为一般规则,最好确保在实施条件渲染时:

  • 不要随意改变部件的位置,以防止不必要地拆卸和重新安装部件。
  • 仅更改与条件呈现有关的标记。
  • 不要在render方法中不必要地膨胀你的组件,因为这会导致组件延迟渲染。

有关更多信息,请参阅这篇关于React中高性能条件句的文章],作者是Cole Williams。

需要考虑的事项包括:

  • 要有条件呈现的标记的大小
  • 可能结果的数量
  • 这样会更直观更易读

一般来说,请牢记以下建议:

  • 对于只有一种预期结果的情况,短路评估可能是最适用的
  • 对于有两个预期结果的情况,使用if…Else语句、元素变量、三元运算符或立即调用的函数表达式可能是最适用的。
  • 对于多于两个结果的情况,最适用的可能是Switch语句、提取的函数或提取的函数组件。

请记住,这些是建议,而不是规则。项目的需求和约定可能要求您采用不遵循这些建议的方法。

结论

在本文中,您研究了在Reaction应用程序中实现条件呈现的七种方法。每种方法都有自己的优点,选择使用哪种方法主要取决于用例。

有关详细信息,请参阅Conditional Rendering.]的文档

继续学习高阶组件使用HOC进行条件渲染

Published At
Categories with 技术
Tagged with
comments powered by Disqus