meteor-react
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact interfaces for Meteor 3
Meteor 3 的 React 界面
React owns component rendering and local UI state. Meteor owns startup,
Tracker reactivity, Minimongo, subscriptions, methods, and the build handoff.
Keep those boundaries visible: components consume authorized client data and
invoke methods, while publications and methods remain the server authority.
React 负责组件渲染和本地UI状态管理。Meteor 负责启动、Tracker响应式、Minimongo、订阅、方法以及构建交接。请明确这些职责边界:组件负责使用已授权的客户端数据并调用方法,而发布和方法则由服务器管控。
Decision flow
决策流程
- For a new JavaScript app, run ; React is also the default skeleton. For TypeScript and TSX, run
meteor create --react <name>.meteor create --typescript <name> - Inspect ,
package.json,.meteor/packages, the client entry, and.meteor/versions. Skeletons andrspack.config.*versions can change independently of this skill.react-meteor-data - Mount one React root from with
Meteor.startup.createRoot - Pick one surface for a component:
react-meteor-data- Classic hooks for explicit loading UI and synchronous Minimongo reads.
- Suspense hooks only when an upstream Suspense fallback and rejection boundary already own the pending and error states.
- Use for readiness,
useSubscribefor reactive lists with stable document references, anduseFindfor other Tracker values.useTracker - Keep React-specific Rspack rules here. Route aliases, loaders, code splitting, cache, output, or migration work to the build skills.
- Test UI behavior in a browser-backed client suite and always unmount the rendered root so Tracker computations and subscriptions can stop.
- 对于新的JavaScript应用,执行 ;React 也是默认的骨架模板。对于TypeScript和TSX项目,执行
meteor create --react <name>。meteor create --typescript <name> - 检查 、
package.json、.meteor/packages、客户端入口文件以及.meteor/versions。骨架模板和rspack.config.*的版本可能独立于本技能更新。react-meteor-data - 在 中使用
Meteor.startup挂载一个React根实例。createRoot - 为组件选择一种 的使用方式:
react-meteor-data- 传统钩子:适用于显式加载UI和同步Minimongo读取场景。
- Suspense钩子:仅当上游已存在Suspense回退组件和错误边界来处理等待和错误状态时使用。
- 使用 处理订阅就绪状态,
useSubscribe获取具有稳定文档引用的响应式列表,useFind处理其他Tracker值。useTracker - React专属的Rspack规则请在此处理。路径别名、加载器、代码分割、缓存、输出或迁移相关工作请转至构建技能。
- 在浏览器端的客户端测试套件中测试UI行为,并且始终卸载渲染的根实例,以便Tracker计算和订阅可以停止。
Current scaffold
当前脚手架
bash
meteor create --react my-app
cd my-app
meteorCurrent Meteor 3.4+ scaffolds use Rspack and . Inspect
: Meteor 3 requires 3.0.0+, these examples target 4.0.1, and
records feature floors.
react-meteor-data.meteor/versionsreferences/react-meteor-data.mdjsx
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 uses , a , and usually
. Meteor discovers that TypeScript config directly.
client/main.tsxtsconfig.jsonrspack.config.tsbash
meteor create --react my-app
cd my-app
meteor当前Meteor 3.4+版本的脚手架使用Rspack和 。检查 :Meteor 3要求版本3.0.0+,以下示例针对4.0.1版本, 记录了功能最低版本要求。
react-meteor-data.meteor/versionsreferences/react-meteor-data.mdjsx
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项目使用 、,通常还会有 。Meteor会自动识别TypeScript配置。
client/main.tsxtsconfig.jsonrspack.config.tsReactive data selection
响应式数据选择
| Need | API | Contract |
|---|---|---|
| Subscription readiness | Classic | Returns an |
| Reactive list | Classic | Return a cursor, never |
| User, count, single document, ReactiveVar | Classic | Return the reactive value. Avoid arbitrary side effects. |
| Async value with Suspense | Suspense | Supply a stable key and Promise-producing function. |
| SSR-capable collection query | Suspense | Pass the collection and the |
| Existing class component | | Keep it during focused maintenance; plan hooks separately. |
Classic list scaffold:
jsx
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>;
}useFinduseTrackerreferences/react-meteor-data.mdskipUpdate| 需求 | API | 约定 |
|---|---|---|
| 订阅就绪状态 | 传统 | 返回一个 |
| 响应式列表 | 传统 | 返回游标,绝不能返回 |
| 用户信息、计数、单个文档、ReactiveVar | 传统 | 返回响应式值,避免任意副作用。 |
| 支持Suspense的异步值 | Suspense | 提供稳定的键和返回Promise的函数。 |
| 支持SSR的集合查询 | Suspense | 传入集合和 |
| 现有类组件 | | 在重点维护期间保留该方式;单独规划钩子迁移。 |
传统列表脚手架示例:
jsx
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>;
}useFinduseTrackerskipUpdatereferences/react-meteor-data.mdSuspense and async reactivity
Suspense与异步响应式
Suspense imports change signatures; they are not drop-in replacements:
jsx
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>
);
}Treat Suspense as a suspension-only call. In the currently
audited package, its declared return type and runtime value disagree, so do not
consume the return. Read for stable keys,
rejections, SSR, and after .
useSubscribereferences/suspense-and-async.mdTracker.withComputationawaitSuspense导入会改变签名,它们不能直接替换传统方式:
jsx
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版 仅视为触发挂起的调用。在当前已审核的包中,其声明的返回类型与运行时值不一致,因此不要使用返回值。如需了解稳定键、错误处理、SSR以及 后的 ,请阅读 。
useSubscribeawaitTracker.withComputationreferences/suspense-and-async.mdBuild and refresh ownership
构建与刷新管控
Rspack detects React from the app's npm dependencies, enables JSX or TSX SWC
parsing, and installs and injects React Refresh for client development. A
normal React Rspack app does not add the refresh plugin manually.
Keep minimal. The generated JavaScript skeleton demonstrates
an optional SVGR rule; the TypeScript skeleton demonstrates type checking.
Compose custom rules through from without
replacing Meteor's SWC defaults.
rspack.config.*defineConfig@meteorjs/rspack| Request | Owner |
|---|---|
| React detection, JSX or TSX, React Refresh boundary | This skill |
General | |
| Convert an existing app or legacy build plugin to Rspack | |
Meteor-bundler HMR or custom | Build skill, then this skill for React symptoms |
If edits reload the page or reset component state, first determine which
bundler compiled the module. In a Rspack client graph, inspect React Refresh
boundaries and avoid a second stack. In a Meteor-bundler
graph, verify and the bundled React Fast Refresh
integration. See .
react-fast-refreshhot-module-replacementreferences/build-refresh-and-testing.mdRspack会从应用的npm依赖中检测React,启用JSX或TSX的SWC解析,并安装和注入React Refresh用于客户端开发。普通的React Rspack应用无需手动添加刷新插件。
保持 尽可能简洁。生成的JavaScript骨架演示了可选的SVGR规则;TypeScript骨架演示了类型检查。通过 的 组合自定义规则,无需替换Meteor的SWC默认配置。
rspack.config.*@meteorjs/rspackdefineConfig| 请求内容 | 负责技能 |
|---|---|
| React检测、JSX/TSX、React Refresh边界 | 本技能 |
通用 | |
| 将现有应用或旧版构建插件转换为Rspack | |
Meteor打包器的HMR或自定义 | 构建技能,之后针对React相关症状使用本技能 |
如果编辑后页面重新加载或组件状态重置,请先确定哪个打包器编译了该模块。在Rspack客户端依赖图中,检查React Refresh边界,避免出现第二个 栈。在Meteor打包器依赖图中,验证 和已打包的React Fast Refresh集成。详情请见 。
react-fast-refreshhot-module-replacementreferences/build-refresh-and-testing.mdMutations and tests
数据变更与测试
Call from event handlers, model pending and rejection in
React state, and leave validation and authorization inside the method. Do not
write sensitive collections directly from a component.
Meteor.callAsyncFor tests, separate a presentational component that accepts data as props from
the hook-owning container. Unit-test the former with the project's existing
React test library. Test the latter in a browser client with controlled
Minimongo or a real publication. Assert rendered behavior, not the number of
reactive-function calls, because React can discard work and invoke initial
render logic more than once.
从事件处理程序中调用 ,在React状态中处理等待和错误状态,将验证和授权逻辑留在方法内部。不要从组件直接写入敏感集合。
Meteor.callAsync对于测试,将接受数据作为props的展示组件与拥有钩子的容器组件分离。使用项目现有的React测试库对展示组件进行单元测试。在浏览器客户端中,使用受控的Minimongo或真实发布对容器组件进行测试。断言渲染行为,而不是响应式函数的调用次数,因为React可能会丢弃工作并多次调用初始渲染逻辑。
Anti-patterns
反模式
- Treat classic as a boolean. It is a function and must be called.
isLoading - Pass to
Tasks.find().fetch(). Return the cursor.useFind - Put a subscription inside a factory. Subscribe separately.
useFind - Call React state setters, methods, analytics, or arbitrary effects inside a
reactive function.
useTracker - Force every classic component onto Suspense. Both surfaces remain useful.
- Reuse a generic Suspense key for unrelated mounted computations.
- Read a Tracker source only after without restoring the computation.
await - Add to project config when Meteor already injected it.
@rspack/plugin-react-refresh - Replace all Rspack SWC options to add one React transform. Extend them.
- Mock away all Meteor data behavior in a component integration test.
- 将传统版 当作布尔值处理。它是一个函数,必须调用。
isLoading - 向 传入
useFind。应返回游标。Tasks.find().fetch() - 在 的工厂函数内部添加订阅。应单独订阅。
useFind - 在 的响应式函数内部调用React状态设置器、方法、分析工具或任意副作用。
useTracker - 强制所有传统组件切换到Suspense。两种方式都有各自的用途。
- 为无关的挂载计算重用通用的Suspense键。
- 在 后读取Tracker数据源但未恢复计算。
await - 当Meteor已自动注入时,仍向项目配置中添加 。
@rspack/plugin-react-refresh - 为添加一个React转换而替换所有Rspack SWC选项。应扩展现有选项。
- 在组件集成测试中模拟所有Meteor数据行为。
Authoritative resources
权威资源
- Meteor React tutorial
- documentation
react-meteor-data - source and changelog
meteor/react-packages - Meteor Rspack integration
- React
createRoot - React Suspense
references/react-meteor-data.mdreferences/suspense-and-async.mdreferences/build-refresh-and-testing.mdreferences/eval-cases.md
- Meteor React 教程
- 文档
react-meteor-data - 源码与变更日志
meteor/react-packages - Meteor Rspack 集成
- React
createRoot - React Suspense
references/react-meteor-data.mdreferences/suspense-and-async.mdreferences/build-refresh-and-testing.mdreferences/eval-cases.md