← Frontend / React

02_路由数据与测试

React 路由、服务端数据获取、取消与缓存、运行时校验和组件测试。

React 路由、数据获取与测试

学习目标:把 React 组件组织成可导航、可请求、可测试的应用。

1. 路由承担可分享状态

使用 React Router 或所选框架的路由系统定义列表、详情、编辑与不存在页面。搜索词和分页放在 URL 查询参数,使刷新与前进后退行为可预测。路由切换时要处理旧请求取消、未保存表单提示和权限失败。

2. 服务端数据不是普通全局状态

数据获取层负责加载、缓存、失效、重试和并发请求去重。可以用维护良好的数据获取库,也可以在小项目里先写一个清晰的 Hook;关键是定义什么时候重新获取,而不是把响应永久复制进全局 store。

import { useEffect, useState } from 'react';

type Note = { id: number; title: string };

export function NoteList() {
  const [notes, setNotes] = useState<Note[]>([]);
  const [error, setError] = useState('');

  useEffect(() => {
    const controller = new AbortController();
    async function load() {
      try {
        const response = await fetch('/api/notes', { signal: controller.signal });
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        const data: unknown = await response.json();
        if (!Array.isArray(data)) throw new Error('Invalid response');
        setNotes(data as Note[]); // 正式项目还需逐字段运行时校验
      } catch (cause) {
        if (!controller.signal.aborted) setError(String(cause));
      }
    }
    void load();
    return () => controller.abort();
  }, []);

  if (error) return <p role="alert">加载失败:{error}</p>;
  return <ul>{notes.map(note => <li key={note.id}>{note.title}</li>)}</ul>;
}

这是教学示例:生产项目还需加载状态、鉴权、错误映射、缓存和完整响应校验。若采用数据获取库,优先使用其取消与缓存机制,不必重复手写。

3. 组件测试

测试用户行为而非组件内部实现。React Testing Library 可通过 getByRole 查找按钮、输入和提示;Mock 网络响应要覆盖成功、空数据、超时、403 与 500。端到端测试再用真实路由与后端检查关键流程。

易错点:`setNotes(data as Note[])` 只是告诉 TypeScript 相信你,不能验证网络数据;正式项目应使用运行时 schema 或显式检查。

自测

  1. 请求返回 200 后,页面是否一定能安全渲染?不一定,还要验证数据形状。
  2. 为什么路由切换时要取消旧请求?避免过期结果覆盖新页面,并减少无用工作。

4. 把 URL 当作可恢复的页面状态

列表的 query、page 或游标放在 URL 中,刷新和分享后仍能还原页面。解析 URL 参数时要处理缺失、非法值和边界值;不要直接把字符串断言成数字。详情页路径使用稳定 ID,切换 ID 后旧请求可能晚于新请求完成,需要取消或忽略过期结果。

5. 请求状态至少有四种

初次加载、成功且有数据、成功但为空、失败分别显示不同界面。取消请求通常不应展示成“服务器错误”。重试策略要分操作:读请求在限定次数内重试可能合理;创建或支付这类写请求必须先考虑幂等,否则重试可能重复执行。

type ListState =
  | { status: 'loading' }
  | { status: 'success'; notes: Note[] }
  | { status: 'error'; message: string };

网络 JSON 是 unknown,先验证数组元素的 id、title 等字段,再转为 Note[]。业务错误如 401、403、409 与网络失败应保留不同代码,让页面给出可操作的反馈。数据获取库能处理缓存与失效,但运行时解析仍是应用自己的责任。

6. 从组件测试到端到端

组件测试用 Mock API 验证:加载时有状态提示,空列表出现空状态,403 显示权限文案,刷新按钮可重新请求。端到端测试用独立测试账号跑“登录—搜索—创建—刷新—编辑—退出”。测试以角色、标签和可见文本定位控件,不依赖组件内部 state。模拟网络慢响应,确认旧搜索结果不会覆盖新结果。