本章将讨论 React(JSX) 的条件判断和循环。

开始学习之前,请大声朗读三遍下面的内容:

如果你还无法区分表达式和语句,可以看看这个文档

条件控制

Javascript 提供了很多用于条件控件的表达式(再次说明,这里要表达式,而不是 if/switch这些语句),部分举例如下:

  • ?::举例 isCheck ? 'red' : 'blue'
  • ??:举例 'foo'??'bar'
  • &&:举例 'foo' && 'bar'
  • ||:举例 'foo' || 'bar'
  • 以及其它

案例:

  • 一个div和一个复选框
  • 初始状态
    • div 的背景颜色是蓝色
    • 复选框未选中
  • 复选框选中后,div的背景颜色变成红色
  • 以上状态切换要做到轮换

初始页面

import React from 'react';

function App() {
  return (
    <div>
      <div
        style={{
          width: '10rem',
          height: '10rem',
          display: 'inline-block',
          background: 'blue',
        }}
      ></div>
      <label>
        <input type="checkbox" />
        变变变
      </label>
    </div>
  );
}

export default App;

加入状态和条件判断

import React, { useState } from 'react';

function App() {
  const [isChecked, setChecked] = useState(false);

  return (
    <div>
      <div
        style={{
          width: '10rem',
          height: '10rem',
          display: 'inline-block',
          background: isChecked ? 'red' : 'blue',
        }}
      ></div>
      <label>
        <input
          type="checkbox"
          checked={isChecked}
          onChange={() => {
            setChecked(!isChecked);
          }}
        />
        变变变
      </label>
    </div>
  );
}

export default App;
  • 第4行:创建名为 isChecked 的状态和对应的状态更新函数,用于保存复选框是否选中
  • 第13行:使用 ?: 运算符进行条件判断
  • 第19行:将 isChecked 状态值设置为复选框 checked 属性的值
  • 第20~22行:使用匿名函数作为事件处理函数,进而改变选中状态

本节代码:axum-rs-jsx-if

key 属性

在动态渲染的时候(比如遍历一个数组生成列表时),该属性必须指定,并且在当前组件内的值必须唯一。

很多人在遍历数组生成列表是,会想当然的用数组的索引作为 key 值,在某些场景这会导致灾难性的后果(比如动态添加、倒序排列列表)。

指定key的原则是:使用后端提供的、能唯一标识的值(比如数据库里的主键ID);除非你知道你在做什么,否则不要用数组索引做key。

key的指定很简单,比如:

<div key="foo"></div>

循环

既然无法使用语句,那在 JSX 中如何遍历数组呢?答案是使用 Javascript 的高阶函数:

  • map()
  • reduce()
  • filter()
  • 以及其它

案例:

使用 React 显示 10 个用户的列表。

  • 第4行:创建用于维护用户列表的状态及其设置函数
  • 第6~22行:用于创建模拟数据。为了模拟从后端获取数据的等待过程,这里使用 setTimeout设置了3秒后才回填数据
  • 第28~32行:使用 map() 来遍历数组
    • 第29行:使用用户的id作为动态组件的key

本节代码:axum-rs-jsx-loop-1

综合案例

下面对用户列表案例进行扩展:在从后端获取数据的时候,显示“正在载入”;获取数据完成之后才显示用户列表。

import React, { useEffect, useState } from 'react';

function App() {
  const [users, setUsers] = useState([]);
  const [isLoading, setLoading] = useState(false);

  useEffect(() => {
    setLoading(true);
    // 模拟从后端获取数据
    setTimeout(() => {
      setUsers([
        { id: 123, name: 'axum.rs-1', age: 18 },
        { id: 456, name: 'axum.rs-2', age: 14 },
        { id: 789, name: 'axum.rs-3', age: 21 },
        { id: 1011, name: 'axum.rs-4', age: 28 },
        { id: 1213, name: 'axum.rs-5', age: 38 },
        { id: 1415, name: 'axum.rs-6', age: 58 },
        { id: 1617, name: 'axum.rs-7', age: 82 },
        { id: 1819, name: 'axum.rs-8', age: 12 },
        { id: 2021, name: 'axum.rs-9', age: 13 },
        { id: 2223, name: 'axum.rs-10', age: 33 },
      ]);
      setLoading(false);
    }, 3000);
  }, []);

  return (
    <div>
      <h1>用户列表</h1>
      {isLoading ? (
        <div>正在载入</div>
      ) : (
        <ul>
          {users.map((user) => (
            <li key={user.id}>
              姓名:{user.name}, 年龄:{user.age}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

export default App;

  • 第5行:创建用于保存是否正在载入的状态 isLoding 及其设置函数
  • 第8行:开始后端获取数据时,将isLoding 设置为true
  • 第23行:获取完数据,将 isLoding 设置为false
  • 第30~40行:根据 isLoading 的值动态呈现不同的组件

本节代码:axum-rs-jsx-loop-2