关于 meteor-react
meteor-react 是一项面向 Meteor 3 应用构建 React 界面的技能,涵盖响应式数据 Hook、渲染、构建配置、数据变更和浏览器测试。
主要功能
- 01挂载 React 根节点
- 02选择 react-meteor-data Hook
- 03显示 Tracker 响应式列表
- 04处理 Suspense 与异步数据
- 05配置 Rspack 和 React Refresh
- 06在浏览器中测试界面行为
适用场景
- 01创建 Meteor 3 React 应用
- 02根据订阅状态显示界面
- 03实现响应式任务列表
- 04测试 Meteor 界面行为
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ meteor/ agent-skills --skill meteor-react安装后在 Claude Code 中输入/meteor-react确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/build-refresh-and-testing.mdeval-cases.mdreact-meteor-data.mdsuspense-and-async.md详细介绍
Meteor 3 的 React 界面
React 负责渲染和本地 UI 状态;Meteor 负责响应式数据和构建交接。组件使用经过授权的数据并调用方法。发布和方法仍由服务器掌控。
决策流程
- 对于新的 JavaScript 应用,运行
meteor create --react <name>;React 也是默认骨架。对于 TypeScript 和 TSX,运行meteor create --typescript <name>。 - 检查
package.json、.meteor/packages、.meteor/versions、客户端入口和rspack.config.*。骨架和react-meteor-data版本可以独立变化。 - 使用
createRoot,从Meteor.startup挂载一个 React 根节点。 - 为组件选择一种
react-meteor-data接口:- 经典 Hooks:用于显式加载 UI 和同步 Minimongo 读取。
- 仅当上游 Suspense fallback 和拒绝边界已负责处理挂起和错误状态时,才使用 Suspense Hooks。
- 使用
useSubscribe获取就绪状态,使用useFind获取具有稳定文档引用的响应式列表,其他 Tracker 值则使用useTracker。 - 在此处保留 React 专用的 Rspack 规则。路由别名、加载器、代码拆分、缓存、输出或迁移工作应交由构建技能处理。
- 在浏览器支持的客户端测试套件中测试 UI 行为,并始终卸载已渲染的根节点,以便停止 Tracker 计算和订阅。
当前脚手架
meteor create --react my-app
cd my-app
meteor
当前 Meteor 3.4+ 脚手架使用 Rspack 和 react-meteor-data。检查
.meteor/versions:Meteor 3 要求版本为 3.0.0+,这些示例以 4.0.1 为目标,而
references/react-meteor-data.md 记录了各项功能所需的最低版本。
import { Meteor } from "meteor/meteor";
import { createRoot } from "react-dom/client";
import { App } from "/imports/ui/App";
import "/imports/ui/styles.css";
Meteor.startup(() => {
const container = document.getElementById("react-target");
if (!container) throw new Error("Missing #react-target");
createRoot(container).render(<App />);
});
TypeScript 使用 client/main.tsx、tsconfig.json,通常还会使用
rspack.config.ts。Meteor 会直接发现该 TypeScript 配置。
响应式数据选择
| 需求 | API | 契约 |
|---|---|---|
| 订阅就绪状态 | 经典 useSubscribe | 返回一个 isLoading 函数。调用它。 |
| 响应式列表 | 经典 useFind | 返回游标,绝不要调用 fetch()。 |
| 用户、计数、单个文档、ReactiveVar | 经典 useTracker | 返回响应式值。避免任意副作用。 |
| 带 Suspense 的异步值 | Suspense useTracker | 提供稳定键和生成 Promise 的函数。 |
| 支持 SSR 的集合查询 | Suspense useFind | 传入集合和 find 参数元组。 |
| 现有类组件 | withTracker | 在有针对性的维护期间保留它;单独规划 Hooks 迁移。 |
经典列表脚手架:
import { useFind, useSubscribe } from "meteor/react-meteor-data";
import { Tasks } from "/imports/api/tasks";
export function TaskList({ listId }) {
const isLoading = useSubscribe("tasks.byList", listId);
const tasks = useFind(
() => Tasks.find({ listId }, { sort: { createdAt: -1 } }),
[listId],
);
if (isLoading()) return <p>Loading...</p>;
if (tasks.length === 0) return <p>No tasks.</p>;
return <ul>{tasks.map((task) => <li key={task._id}>{task.title}</li>)}</ul>;
}
useFind 负责游标观察,并且只更新发生变化的文档引用。
如果转换后的聚合结果更清晰,请使用 useTracker。调整依赖项或 skipUpdate 前,请阅读
references/react-meteor-data.md。
Suspense 和异步响应性
Suspense 导入会改变签名;它们不能直接替换:
import { Suspense } from "react";
import { useFind, useSubscribe } from "meteor/react-meteor-data/suspense";
import { Tasks } from "/imports/api/tasks";
function TaskList({ listId }) {
useSubscribe("tasks.byList", listId);
const tasks = useFind(Tasks, [
{ listId },
{ sort: { createdAt: -1 } },
], [listId]);
return <ul>{tasks.map((task) => <li key={task._id}>{task.title}</li>)}</ul>;
}
export function TaskScreen({ listId }) {
return (
<AppErrorBoundary>
<Suspense fallback={<p>Loading...</p>}>
<TaskList listId={listId} />
</Suspense>
</AppErrorBoundary>
);
}
将 Suspense useSubscribe 视为仅用于挂起的调用。在当前审查过的
软件包中,其声明的返回类型与运行时值不一致,因此不要使用其返回值。有关稳定键、
拒绝、SSR 以及 await 之后的 Tracker.withComputation,请阅读 references/suspense-and-async.md。
构建与刷新归属
Rspack 会从应用的 npm 依赖中检测 React,启用 JSX 或 TSX 的 SWC 解析,并在客户端开发期间安装和注入 React Refresh。常规的 React Rspack 应用无需手动添加刷新插件。
保持 rspack.config.* 简洁。生成的 JavaScript 骨架展示了一个可选的 SVGR 规则;TypeScript 骨架展示了类型检查。
使用 @meteorjs/rspack 中的 defineConfig 组合自定义规则,同时保留 Meteor 的 SWC 默认配置。
对于 React Compiler,Meteor 3.6-beta.0 组合支持 SWC;较旧的组合可以继续使用 Babel。请阅读编译器设置,了解 React 版本目标和运行时要求。
| 请求 | 归属 |
|---|---|
| React 检测、JSX 或 TSX、React Refresh 边界 | 此技能 |
通用 rspack.config 辅助工具、SWC、别名、缓存、代码块 | meteor-modern-build-stack |
| 将现有应用或旧版构建插件转换为 Rspack | migrate-to-rspack |
Meteor-bundler HMR 或自定义 module.hot 生命周期 | 构建技能;React 相关症状则由此技能处理 |
如果编辑导致页面重新加载或组件状态重置,请先确定哪个打包器编译了该模块。在 Rspack 客户端依赖图中,检查 React Refresh 边界,并避免叠加第二套 react-fast-refresh。在 Meteor-bundler 依赖图中,确认已启用 hot-module-replacement 和捆绑的 React Fast Refresh 集成。请参阅 references/build-refresh-and-testing.md。
变更与测试
在事件处理程序中调用 Meteor.callAsync,在 React 状态中管理等待和拒绝状态,并将验证和授权留在方法内部。不要直接从组件写入敏感集合。
进行测试时,将接收数据作为属性的展示型组件与持有 Hook 的容器分开。使用项目现有的 React 测试库对前者进行单元测试。在浏览器客户端中,使用受控的 Minimongo 或真实发布来测试后者。断言渲染行为,而不是响应式函数的调用次数,因为 React 可能会丢弃工作,并多次调用初始渲染逻辑。
反模式
- 将经典的
isLoading视为布尔值。它是一个函数,必须调用。 - 将
Tasks.find().fetch()传给useFind。应返回游标。 - 在
useFind工厂中放置订阅。应单独订阅。 - 在
useTracker响应式函数中调用 React 状态设置器、方法、分析工具或任意副作用。 - 强制所有经典组件使用 Suspense。两种用法都仍然适用。
- 对无关的已挂载计算复用通用 Suspense 键。
- 在
await之后读取 Tracker 源,却不恢复计算上下文。 - 当 Meteor 已经注入
@rspack/plugin-react-refresh时,仍将其添加到项目配置中。 - 为添加一个 React 转换而替换所有 Rspack SWC 选项。应扩展它们。
- 在组件集成测试中完全模拟掉 Meteor 数据行为。
权威资源
- Meteor React 教程
react-meteor-data文档meteor/react-packages源码与变更日志- Meteor Rspack 集成
- React
createRoot - React Suspense
references/eval-cases.md