Skip to content
第 6 章 前端 ⏱ 12 分钟阅读

第 6 章:条件与列表 ​

学习目标 ​

  • 掌握 4 种条件渲染写法
  • 熟练运用 map 渲染列表
  • 理解 key 的作用与最佳实践
  • 避开条件/列表渲染的 4 个坑

一、条件渲染的 4 种写法 ​

写法 1:if-else(早返回) ​

适合组件级别分支,早 return:

tsx
function Page({ status }: { status: 'loading' | 'ok' | 'empty' | 'error' }) {
  if (status === 'loading') return <Spinner />;
  if (status === 'error') return <ErrorPage />;
  if (status === 'empty') return <Empty />;
  return <Content />;
}

优点:逻辑清晰,避免深层嵌套。

写法 2:三元运算符 ​

适合有 else 分支的内联场景:

tsx
function Button({ disabled }: { disabled: boolean }) {
  return (
    <button disabled={disabled}>
      {disabled ? '已禁用' : '点击'}
    </button>
  );
}

写法 3:&& 短路 ​

只关心 true 时渲染,不关心 false:

tsx
function Notice({ hasMsg }: { hasMsg: boolean }) {
  return (
    <div>
      {hasMsg && <span>你有一条新消息</span>}
    </div>
  );
}

⚠️ 坑 1:count && <Badge /> 当 count = 0 会渲染数字 0!必须写 count > 0 && <Badge />。

写法 4:switch ​

适合枚举多分支:

tsx
function StatusBadge({ s }: { s: 'ok' | 'warn' | 'err' }) {
  switch (s) {
    case 'ok': return <span className="ok">正常</span>;
    case 'warn': return <span className="warn">警告</span>;
    case 'err': return <span className="err">异常</span>;
  }
}

二、列表渲染基础 ​

tsx
interface User { id: number; name: string; }

function UserList({ users }: { users: User[] }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>
          {user.name}
        </li>
      ))}
    </ul>
  );
}

必须给列表项设 key,否则 React 警告且性能差。

三、key 的关键作用 ​

React 用 key 匹配前后两次渲染的元素:

场景没 key有 key
列表顺序变化全部销毁重建复用 DOM/状态
性能差快
组件 state错乱正确
tsx
// ✅ 用稳定、唯一 ID
{items.map(item => <Item key={item.id} {...item} />)}

// ❌ 用 index(顺序变化就出问题)
{items.map((item, i) => <Item key={i} {...item} />)}

⚠️ 坑 2:即使你看不到 bug,永远不要用 index 当 key,除非列表只读、永不重排、永不增删。

四、空列表与边界 ​

tsx
function List({ items }: { items: string[] }) {
  if (items.length === 0) return <Empty />;        // ✅ 早返回
  return <ul>{items.map(...)}</ul>;
}

// 或者
function List({ items }: { items: string[] }) {
  return (
    <>
      {items.length === 0
        ? <Empty />
        : <ul>{items.map(...)}</ul>}
    </>
  );
}

五、嵌套列表 ​

tsx
function GroupList({ groups }: { groups: Group[] }) {
  return (
    <div>
      {groups.map(group => (
        <section key={group.id}>
          <h3>{group.name}</h3>
          <ul>
            {group.items.map(item => (
              <li key={item.id}>{item.text}</li>
            ))}
          </ul>
        </section>
      ))}
    </div>
  );
}

⚠️ 坑 3:外层和内层的 key 必须都设,不能只设一层。

六、分页 / 切片 ​

tsx
function PaginatedList({ items, page, pageSize }: Props) {
  const start = (page - 1) * pageSize;
  const visible = items.slice(start, start + pageSize);

  return (
    <>
      {visible.map(item => <Card key={item.id} {...item} />)}
      <Pagination total={items.length} pageSize={pageSize} />
    </>
  );
}

七、过滤 / 搜索 ​

tsx
function SearchableList({ items, keyword }: Props) {
  const filtered = items.filter(item =>
    item.name.toLowerCase().includes(keyword.toLowerCase())
  );

  if (filtered.length === 0) return <Empty text="无匹配结果" />;
  return <ul>{filtered.map(...)}</ul>;
}

八、本章小结 ​

要点关键
条件渲染if 早返 / 三元 / && / switch
&& 陷阱数字 0 会渲染,必须加判断
列表渲染array.map + 唯一 key
key 选择稳定业务 ID,禁用 index
空数据早返回 <Empty />
嵌套列表每层都要 key

动手练习 ​

  1. 状态徽章:根据 status 显示「加载中/成功/失败/空」四种界面
  2. 学生列表:渲染 5 个学生,带搜索框过滤(实时)
  3. 分组列表:按 category 分组的卡片,每组渲染该组项
  4. 找坑:以下代码点击按钮会发生什么?
    tsx
    const [count, setCount] = useState(0);
    return <div>{count && <Badge count={count} />}</div>;

下一章:第 7 章:表单 →

本站基于 VitePress 构建 · 由 StackHub 团队维护