# Hook 与数据请求 ## API 适配三件套 服务端数据按 feature 放置为 API 函数、query hook 和类型文件: 1. `features/system/api/system.types.ts` 定义 `SystemStatus`。 2. `features/system/api/system.api.ts:getSystemStatus` 调用 shared transport,并把 `AbortSignal` 传给 `fetch`。 3. `features/system/api/system.query.ts:useSystemStatus` 暴露 React Query hook,并使用 `systemStatusQueryKey`。 页面只调用 `useSystemStatus`,不直接调用 `fetch`。新增 feature 应保持同样分层。 ```ts export const systemStatusQueryKey = ["system", "status"] as const export function useSystemStatus() { return useQuery({ queryFn: ({ signal }) => getSystemStatus(signal), queryKey: systemStatusQueryKey, }) } ``` ## React Query - 服务器状态由 TanStack Query 管理;公共默认值在 `app/query-client.ts`(不跟随窗口刷新、失败重试 1 次、`staleTime` 30 秒)。 - query key 使用 `as const` 常量,避免页面散落字符串。 - 使用 query function 提供的 `signal` 支持取消请求;不要忽略它或在页面手写生命周期 fetch。 - 页面显式处理 `isPending`、`isError` 和 `data`,参照 `SystemStatusPage`。 ## Hook 命名与副作用 - 自定义 hook 以 `use` 开头并表达资源或行为,例如 `useSystemStatus`、`useUiStore`。 - 纯数据 hook 不执行额外副作用;需要同步 DOM 的副作用集中在 `app/providers.tsx:ThemeEffect`,由 Zustand 主题驱动 `document.documentElement` 的 class。 - 不要把一个 hook 同时用作服务器缓存和 UI 偏好存储;两者分别使用 React Query 与 Zustand。 ## 反模式 - 不要在组件中直接 `fetch`、重复设置 query key 或把响应复制到本地 `useState`。 - 不要用 Zustand 保存 API 响应以“共享”数据,也不要用 React Query 保存主题等本地偏好。 - 不要为了复用一次性的 `useEffect` 创建泛化 hook;先确认是否已有跨页面重复模式。