状态与数据查询
状态放在哪里
服务端数据由 TanStack Query 管理;网址可分享的状态放路由查询参数;组件短期状态用 React;跨组件的纯界面状态可使用 Jotai。不要把会话、订阅和积分复制到多个状态容器。
统一查询客户端在 apps/app/lib/query.ts:一般查询新鲜期为两分钟,网络重新连接时刷新;变更默认不重试,避免响应丢失后重复创建记录。
会话查询
apps/app/lib/queries/session.ts 使用固定查询键 ['auth', 'session'],新鲜期为 30 秒。用户和会话同时存在才算登录;401、403 不自动重试,网络错误可以重试。组件用 useSessionQuery(),路由守卫使用同一查询配置。
注册、登录或切换活动组织后调用 revalidateSession(),删除旧会话查询并重新运行路由守卫。退出只有在服务端成功后才清空会话并跳转登录。
业务查询
查询集中在 apps/app/lib/queries/。组织查询键包含组织 ID;没有活动组织时跳过请求。写入成功后只刷新受影响的数据,避免把所有查询一起失效。
tsx
import { useSessionQuery } from "#lib/queries/session";
import { useMembersQuery } from "#lib/queries/organization";
export function MemberCount() {
const session = useSessionQuery();
const members = useMembersQuery(session.data?.session.activeOrganizationId);
if (members.isPending) return <p>正在读取成员</p>;
if (members.error) return <p>成员读取失败</p>;
return <p>成员数量:{members.data?.members.length ?? 0}</p>;
}这个组件示例用于说明查询依赖;无活动组织时应提供创建组织入口,而不是永久显示加载中。
排查缓存问题
先检查查询键是否包含用户或组织范围,再检查失效逻辑。权限和账单还需要服务端使用 ctx.db 的实时连接,前端刷新无法修正后端缓存了旧权限的问题。