Eazo 生成的页面里,展示层通常能直接用:布局、样式、响应式、通用组件和交互骨架大多可以留;数据层与请求层通常要自己补:写死的示例数组、模拟请求、接口地址、字段命名和错误处理,基本都要按自有后端重写。判断一个文件该留还是该改,先看它是否只依赖 props 或静态内容,而不是看它长得是否完整。
适用场景:用 Eazo 生成页面后准备接自有后端。操作动作:按文件把展示层与数据层分开,保留纯展示组件,把写死数据、请求地址、字段映射逐处登记后重写。验证方式:用一条真实数据从列表点进详情,在 Network 面板确认请求 URL 与响应,页面不出现 undefined。风险边界:鉴权方式、分页约定、枚举值含义无法从生成代码推断时不要猜,需与接口方确认后再定。
沿页面文件确认哪些组件可以直接留用
生成代码一般按语义命名:页面级文件在 pages/、app/、views/ 下,通用块在 components/ 下,名字多为 Layout、Header、Sidebar、CardList、DataTable、FilterBar、DetailPanel、EmptyState、Pagination。先按目录和文件名过一遍,比逐行读代码快,也方便把改数据和改样式分开排期。
可以直接留用的判断标准:
- 组件只接收 props 或 children,文件里没有 import 数据文件,也没有 fetch、axios 调用;
- 模板里的文案、图标、间距属于通用内容,不绑定某个业务字段名;
- 加载态、空态、错误态的展示分支齐全,不需要重新设计;
- 没有对字段做固定换算,例如金额除 100、时间戳乘 1000。
需要改的组件特征更明显:useState 的初始值是一个具体示例数组;useEffect 里直接请求或用 setTimeout 造数据;模板直接读 item.title、item.statusText 这类 mock 字段名;分页、排序、筛选是前端对静态数组做 slice 或 sort。这类组件保留外壳,把数据来源和执行逻辑换掉。
建议边看边登记,避免改到一半记不清:
| 文件路径 | 组件 | 结论 | 原因 |
|---|---|---|---|
| src/components/StatCard.jsx | StatCard | 留用 | 只吃 props |
| src/pages/OrderList.jsx | OrderList | 改数据 | 内联 mock 数组加 setTimeout |
| src/pages/UserDetail.jsx | UserDetail | 重写请求 | 字段名与后端不一致 |
找出数据来源被写死的位置
写死数据通常有四种形态:顶层常量数组(const listData = [...])、独立 mock 文件(mock/、fixtures/、__mocks__ 目录或 data.js)、组件内联数组(map 里直接写对象)、假装成请求的异步函数(setTimeout 里 resolve 一个常量)。前三种搜变量名和关键词能找到,第四种要看有没有 fetch 或 Promise.resolve。
可以先跑几条搜索把范围缩小:
grep -rnE 'mock|dummy|sample|fake|placeholder' src
grep -rnE 'setTimeout|Promise\.resolve|axios|fetch\(' src
grep -rn 'const .* = \[' src
逐处登记用一张短清单就够,每行四列:编号、文件与行号、写死类型、替换目标(哪个接口、哪些字段)。类型分三类即可:内联常量、独立 mock 文件、模拟请求。登记后按清单逐条改,改完划掉,比靠记忆核对可靠。
把请求逻辑单独抽成一层便于替换地址
组件里出现请求地址时,把它上移到单独一层:组件只调 api 模块的函数,api 模块调统一 request,request 读环境变量里的 base 地址。这样换地址、加 header、改错误处理都只动一处。
// src/api/request.js
const BASE = import.meta.env.VITE_API_BASE || '/api';
export async function request(path, options = {}) {
const res = await fetch(BASE + path, {
headers: { 'Content-Type': 'application/json', ...(options.headers || {}) },
...options,
});
if (!res.ok) throw new Error('HTTP ' + res.status);
return res.json();
}
// src/api/order.js
import { request } from './request';
export const getOrderList = (params) =>
request('/orders?' + new URLSearchParams(params).toString());
export const getOrderDetail = (id) => request('/orders/' + id);
环境变量按框架约定读取:Vite 用 .env 里的 VITE_API_BASE,代码写 import.meta.env.VITE_API_BASE;Next.js 用 .env.local 里的 NEXT_PUBLIC_API_BASE,代码写 process.env.NEXT_PUBLIC_API_BASE,只有带公开前缀的变量才会进到浏览器端。改完 .env 通常要重启 dev server,变量多在启动或构建时注入。
替换后的验证三步:一是在 request.js 里临时打印 BASE,确认取到的是自有地址而不是空值;二是打开 Network 面板刷新页面,看请求 URL 前缀是否与 .env 一致;三是把 BASE 临时改成一个不可达地址,确认页面走错误分支而不是白屏。验证完把临时日志删掉。
用一条自有数据走通列表到详情的链路
不必等所有接口就绪,先拿一条真实数据把列表到详情走通。检查点按顺序看:列表接口返回的是数组还是包了一层,res.data 与 res.data.list 的层级要和页面取值一致;列表每条记录的唯一标识字段名(id、_id、orderId)要和详情请求参数、路由参数对得上;详情页从 URL 取的 id 要和请求拼接的参数是同一个值;详情返回的字段名要和模板里读的字段名逐项对应;加载态、空态、错误态三个分支都能手动触发一次。
字段缺失时页面表现往往不明显:模板里 ${item.name} 会渲染出字符串 undefined;参与数字计算会得到 NaN;日期格式化会出现 Invalid Date;列表 key 用下标、字段又缺失时,React 可能复用错误节点,看起来像数据串了;图片 src 为空时浏览器会对当前页面再发一次请求,Network 里能看到。
确认渲染成功的做法:Network 中列表与详情各出现一次成功响应,且响应体里确实有数据;Elements 面板里列表条数等于响应条数;详情页每个字段和接口返回逐项对照一遍;控制台没有 key 重复警告和 undefined 相关报错。任一不满足,先回到第 2 节的写死清单,确认是不是还有旧数据在渲染。
把仍依赖生成假设的部分标注出来
有些假设无法靠搜索发现,只能标出来:接口没返回的字段(头像、昵称、备注)、单位不明的数值(分还是元、秒还是毫秒、时间戳还是 ISO 字符串)、分页与排序约定(page 从 0 还是 1、排序字段名、size 上限)、枚举值与文案的映射、时区、鉴权方式(token 放 header 还是 cookie)、错误码结构。
标注建议统一用可搜索的注释,格式固定,方便最后一次性清理:
// TODO(DATA): 详情接口未返回 author.avatar,暂用占位图,待确认
// TODO(DATA): status 枚举含义未知,当前按 0/1/2 映射文案,待后端确认
// TODO(DATA): amount 单位可能是分,展示与提交前的换算位置待确认
外部再维护一份清单,和注释内容对应:
| 编号 | 文件:行 | 依赖的假设 | 影响范围 | 处理方式 |
|---|---|---|---|---|
| 1 | src/pages/OrderDetail.jsx:42 | 未返回 author.avatar | 头像展示 | 占位图,待确认 |
| 2 | src/pages/OrderList.jsx:18 | status 枚举未知 | 状态文案 | 待接口方给映射表 |
| 3 | src/utils/format.js:7 | amount 单位为分 | 金额展示 | 确认后决定换算位置 |
处理顺序按是否阻塞联调分两批:阻塞的(id 字段、分页约定、鉴权、错误码)先找接口方确认,确认前不要靠猜写死;只影响展示的(占位图、文案、格式化)可以先用占位实现,但保留注释。每条处理完就把 TODO(DATA) 改成实际代码或删除,最后用 grep -rn 'TODO(DATA)' src 对一遍,剩余项应当都是有意识保留的。