Skip to content

react-meteor-data

此软件包提供了 React 与 Tracker(Meteor 的响应式数据系统)的集成。

¥This package provides an integration between React and Tracker, Meteor's reactive data system.

目录

¥Table of Contents

安装

¥Install

提示

此包包含在 React 选项的 meteor create 中。无需手动安装。

¥This package is included with meteor create on react options. No need to install it manually.

要安装此软件包,请使用 meteor add

¥To install the package, use meteor add:

bash
meteor add react-meteor-data

如果你还没有安装 react,则还需要安装它:

¥You'll also need to install react if you have not already:

bash
meteor npm install react

更新日志

¥Changelog

点击此处查看最新更改

¥check recent changes here

用法

¥Usage

此软件包提供了两种在 React 组件中使用 Tracker 响应式数据的方法:

¥This package provides two ways to use Tracker reactive data in your React components:

  • a 钩子:useTracker(仅限 v2,需要 React ^16.8

    ¥a hook: useTracker (v2 only, requires React ^16.8)

  • 高阶组件 (HOC):withTracker(v1 和 v2)。

    ¥a higher-order component (HOC): withTracker (v1 and v2).

useTracker 钩子在 2.0.0 版本中引入,它兼容 钩子的优势。与所有 React hooks 一样,它只能在函数组件中使用,不能在类组件中使用。

¥The useTracker hook, introduced in version 2.0.0, embraces the benefits of hooks. Like all React hooks, it can only be used in function components, not in class components.

withTracker HOC 可以与所有组件、函数或基于类的组件一起使用。

¥The withTracker HOC can be used with all components, function or class based.

无需重写现有应用即可使用 useTracker hook 替代现有的 withTracker HOC。

¥It is not necessary to rewrite existing applications to use the useTracker hook instead of the existing withTracker HOC.

useTracker(reactiveFn)

你可以使用 useTracker hook 获取 React "功能组件。" 中 Tracker 响应式函数的值。每当响应式输入发生变化时,响应式函数都会重新运行,组件将使用新值重新渲染。

¥You can use the useTracker hook to get the value of a Tracker reactive function in your React "function components." The reactive function will get re-run whenever its reactive inputs change, and the component will re-render with the new value.

useTracker 管理其自身状态,并在必要时进行重新渲染。无需在 reactiveFn 内部调用 React 状态设置器。相反,请从 reactiveFn 返回值并将其直接赋值给变量。当 reactiveFn 更新时,变量也会更新,React 组件也会重新渲染。

¥useTracker manages its own state, and causes re-renders when necessary. There is no need to call React state setters from inside your reactiveFn. Instead, return the values from your reactiveFn and assign those to variables directly. When the reactiveFn updates, the variables will be updated, and the React component will re-render.

参数:

¥Arguments:

  • reactiveFn:一个 Tracker 响应函数(接收当前计算)。

    ¥reactiveFn: A Tracker reactive function (receives the current computation).

使用 useTracker 的基本方法是简单地将一个响应式函数传递给它,无需其他操作。在很多情况下,这是首选配置。

¥The basic way to use useTracker is to simply pass it a reactive function, with no further fuss. This is the preferred configuration in many cases.

useTracker(reactiveFn, deps)

你可以传递一个可选的 deps 数组作为第二个值。提供后,计算将被保留,并且首次运行后的响应式更新将从 React 渲染执行框架异步运行。此数组通常包含作为第一个参数传递的闭包中外部作用域 "captured" 的所有变量。例如,订阅或 minimongo 查询中使用的 prop 的值;参见以下示例。

¥You can pass an optional deps array as a second value. When provided, the computation will be retained, and reactive updates after the first run will run asynchronously from the react render execution frame. This array typically includes all variables from the outer scope "captured" in the closure passed as the 1st argument. For example, the value of a prop used in a subscription or a minimongo query; see example below.

对于计算运行时间较长的情况,这应被视为底层优化步骤。 - 就像一个复杂的 minimongo 查询。在许多情况下,省略依赖并允许计算与渲染同步运行是安全的,甚至是更可取的做法。

¥This should be considered a low level optimization step for cases where your computations are somewhat long running - like a complex minimongo query. In many cases it's safe and even preferred to omit deps and allow the computation to run synchronously with render.

参数:

¥Arguments:

jsx
import { useTracker } from 'meteor/react-meteor-data';

// React function component.
function Foo({ listId }) {
  // This computation uses no value from the outer scope,
  // and thus does not needs to pass a 'deps' argument.
  // However, we can optimize the use of the computation
  // by providing an empty deps array. With it, the
  // computation will be retained instead of torn down and
  // rebuilt on every render. useTracker will produce the
  // same results either way.
  const currentUser = useTracker(() => Meteor.user(), []);

  // The following two computations both depend on the
  // listId prop. When deps are specified, the computation
  // will be retained.
  const listLoading = useTracker(() => {
    // Note that this subscription will get cleaned up
    // when your component is unmounted or deps change.
    const handle = Meteor.subscribe('todoList', listId);
    return !handle.ready();
  }, [listId]);
  const tasks = useTracker(() => Tasks.find({ listId }).fetch(), [listId]);

  return (
    <h1>Hello {currentUser.username}</h1>
    {listLoading ? (
        <div>Loading</div>
      ) : (
        <div>
          Here is the Todo list {listId}:
          <ul>
            {tasks.map(task => (
              <li key={task._id}>{task.label}</li>
            ))}
          </ul>
        </div>
      )}
  );
}

注意:eslint-plugin-react-hooks 包提供了 ESLint 提示,以帮助检测 React 内置钩子函数 deps 参数中的缺失值。它可以配置为验证 useTracker 钩子或其他钩子的 deps 参数,使用以下 eslintrc 配置:

¥Note: the eslint-plugin-react-hooks package provides ESLint hints to help detect missing values in the deps argument of React built-in hooks. It can be configured to also validate the deps argument of the useTracker hook or some other hooks, with the following eslintrc config:

json
"react-hooks/exhaustive-deps": ["warn", { "additionalHooks": "useTracker|useSomeOtherHook|..." }]

useTracker(reactiveFn, deps, skipUpdate)useTracker(reactiveFn, skipUpdate)

¥useTracker(reactiveFn, deps, skipUpdate) or useTracker(reactiveFn, skipUpdate)

你可以选择将函数作为第二或第三个参数传递。skipUpdate 函数可以评估 reactiveFn 的返回值以判断更改,并在敏感情况下控制重新渲染。注意:这不适用于深度比较(即使是快速深度相等),因为在很多情况下,这实际上可能导致比允许 React 执行其操作更差的性能。但举例来说,如果你在订阅中没有使用整个文档,则可以使用它来比较更新之间的 updatedAt 字段或特定字段的子集。与任何优化一样,先测量,再优化。在实现之前,请确保你确实需要此功能。

¥You may optionally pass a function as a second or third argument. The skipUpdate function can evaluate the return value of reactiveFn for changes, and control re-renders in sensitive cases. Note: This is not meant to be used with a deep compare (even fast-deep-equals), as in many cases that may actually lead to worse performance than allowing React to do it's thing. But as an example, you could use this to compare an updatedAt field between updates, or a subset of specific fields, if you aren't using the entire document in a subscription. As always with any optimization, measure first, then optimize second. Make sure you really need this before implementing it.

参数:

¥Arguments:

  • reactiveFn

  • deps? - optional - 你可以省略此步骤,或传递 "falsy" 值。

    ¥deps? - optional - you may omit this, or pass a "falsy" value.

  • skipUpdate - 一个接收两个参数的函数:(prev, next) => (prev === next)prevnext 的类型或数据形状将与 reactiveFn 返回的类型或数据形状匹配。注意:返回值为 true 表示更新将为 "skipped"。false 表示重新渲染将照常进行。因此,该函数应该寻找等价关系。

    ¥skipUpdate - A function which receives two arguments: (prev, next) => (prev === next). prev and next will match the type or data shape as that returned by reactiveFn. Note: A return value of true means the update will be "skipped". false means re-render will occur as normal. So the function should be looking for equivalence.

jsx
import { useTracker } from 'meteor/react-meteor-data';

// React function component.
function Foo({ listId }) {
  const tasks = useTracker(
    () => Tasks.find({ listId }).fetch(), [listId],
    (prev, next) => {
      // prev and next will match the type returned by the reactiveFn
      return prev.every((doc, i) => (
        doc._id === next[i] && doc.updatedAt === next[i]
      )) && prev.length === next.length;
    }
  );

  return (
    <h1>Hello {currentUser.username}</h1>
    <div>
      Here is the Todo list {listId}:
      <ul>
        {tasks.map(task => (
          <li key={task._id}>{task.label}</li>
        ))}
      </ul>
    </div>
  );
}

withTracker(reactiveFn)

你可以使用 withTracker HOC 封装你的组件,并从 Tracker 响应式函数中向它们传递额外的 props 值。每当响应式输入发生变化时,响应式函数都会重新运行,并且封装后的组件将使用新添加的 props 值重新渲染。

¥You can use the withTracker HOC to wrap your components and pass them additional props values from a Tracker reactive function. The reactive function will get re-run whenever its reactive inputs change, and the wrapped component will re-render with the new values for the additional props.

参数:

¥Arguments:

  • reactiveFn:一个 Tracker 响应式函数,获取 props 作为参数,并返回一个包含额外 props 的对象以传递给封装组件。

    ¥reactiveFn: a Tracker reactive function, getting the props as a parameter, and returning an object of additional props to pass to the wrapped component.

jsx
import { withTracker } from 'meteor/react-meteor-data';

// React component (function or class).
function Foo({ listId, currentUser, listLoading, tasks }) {
  return (
    <h1>Hello {currentUser.username}</h1>
    {listLoading ?
      <div>Loading</div> :
      <div>
        Here is the Todo list {listId}:
        <ul>{tasks.map(task => <li key={task._id}>{task.label}</li>)}</ul>
      </div}
  );
}

export default withTracker(({ listId }) => {
  // Do all your reactive data access in this function.
  // Note that this subscription will get cleaned up when your component is unmounted
  const handle = Meteor.subscribe('todoList', listId);

  return {
    currentUser: Meteor.user(),
    listLoading: !handle.ready(),
    tasks: Tasks.find({ listId }).fetch(),
  };
})(Foo);

返回的组件在渲染时,除了渲染响应式函数的结果外,还将渲染 Foo("lower-order" 组件)及其提供的 props。因此,Foo 将接收 { listId }(由其父级提供)以及 { currentUser, listLoading, tasks }(由 withTracker HOC 添加)。

¥The returned component will, when rendered, render Foo (the "lower-order" component) with its provided props in addition to the result of the reactive function. So Foo will receive { listId } (provided by its parent) as well as { currentUser, listLoading, tasks } (added by the withTracker HOC).

更多信息,请参阅 Meteor 指南中的 React 文章

¥For more information, see the React article in the Meteor Guide.

withTracker({ reactiveFn, pure, skipUpdate })

withTracker HOC 可以接收配置对象,而不是简单的响应式函数。

¥The withTracker HOC can receive a config object instead of a simple reactive function.

  • getMeteorData - reactiveFn.

  • pure - 默认为 true。导致生成的容器使用 React 的 memo() 进行封装。

    ¥pure - true by default. Causes the resulting Container to be wrapped with React's memo().

  • skipUpdate - 一个接收两个参数的函数:(prev, next) => (prev === next)prevnext 的类型或数据形状将与 reactiveFn 返回的类型或数据形状匹配。注意:返回值为 true 表示更新将为 "skipped"。false 表示重新渲染将照常进行。因此,该函数应该寻找等价关系。

    ¥skipUpdate - A function which receives two arguments: (prev, next) => (prev === next). prev and next will match the type or data shape as that returned by reactiveFn. Note: A return value of true means the update will be "skipped". false means re-render will occur as normal. So the function should be looking for equivalence.

jsx
import { withTracker } from 'meteor/react-meteor-data';

// React component (function or class).
function Foo({ listId, currentUser, listLoading, tasks }) {
  return (
    <h1>Hello {currentUser.username}</h1>
    {listLoading ?
      <div>Loading</div> :
      <div>
        Here is the Todo list {listId}:
        <ul>{tasks.map(task => <li key={task._id}>{task.label}</li>)}</ul>
      </div}
  );
}

export default withTracker({
  getMeteorData ({ listId }) {
    // Do all your reactive data access in this function.
    // Note that this subscription will get cleaned up when your component is unmounted
    const handle = Meteor.subscribe('todoList', listId);

    return {
      currentUser: Meteor.user(),
      listLoading: !handle.ready(),
      tasks: Tasks.find({ listId }).fetch(),
    };
  },
  pure: true,
  skipUpdate (prev, next) {
    // prev and next will match the shape returned by the reactiveFn
    return (
      prev.currentUser?._id === next.currentUser?._id
    ) && (
      prev.listLoading === next.listLoading
    ) && (
      prev.tasks.every((doc, i) => (
        doc._id === next[i] && doc.updatedAt === next[i]
      ))
      && prev.tasks.length === next.tasks.length
    );
  }
})(Foo);

useSubscribe(subName, ...args)

useSubscribe 是设置订阅的便捷简写。它在与 useFind 配合使用时尤其有用,useFind 不应用于设置订阅。其核心是 useTracker 的一个非常简单的封装器(没有依赖),用于以安全的方式创建订阅,并允许你避免定义工厂和定义依赖的一些繁琐步骤。只需传递你的订阅名称和参数即可。

¥useSubscribe is a convenient short hand for setting up a subscription. It is particularly useful when working with useFind, which should NOT be used for setting up subscriptions. At its core, it is a very simple wrapper around useTracker (with no deps) to create the subscription in a safe way, and allows you to avoid some of the ceremony around defining a factory and defining deps. Just pass the name of your subscription, and your arguments.

useSubscribe 返回一个 isLoading 函数。你可以调用 isLoading() 来响应订阅加载状态的变化。isLoading 函数将返回订阅的加载状态,并为加载状态的变化设置响应式。如果你不调用此函数,则加载状态更改时不会发生重新渲染。

¥useSubscribe returns an isLoading function. You can call isLoading() to react to changes in the subscription's loading state. The isLoading function will both return the loading state of the subscription, and set up a reactivity for the loading state change. If you don't call this function, no re-render will occur when the loading state changes.

jsx
// Note: isLoading is a function!
const isLoading = useSubscribe("posts", groupId);
const posts = useFind(() => Posts.find({ groupId }), [groupId]);

if (isLoading()) {
  return <Loading />;
} else {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post._id}>{post.title}</li>
      ))}
    </ul>
  );
}

如果你想有条件地订阅,可以将 name 字段(第一个参数)设置为假值以绕过订阅。

¥If you want to conditionally subscribe, you can set the name field (the first argument) to a falsy value to bypass the subscription.

jsx
const needsData = false;
const isLoading = useSubscribe(needsData ? "my-pub" : null);

// When a subscription is not used, isLoading() will always return false

useFind(cursorFactory, deps)

useFind 钩子可以显著加快来自 mongo 查询(订阅)列表的渲染(和重新渲染)。它通过控制文档对象引用来实现这一点。通过在钩子中提供高度定制的游标管理,使用 Cursor.observe API,useFind 会谨慎地仅更新在 DDP 更新期间更改的对象引用。这种方法可以更紧密地利用核心 React 工具和理念,从而增强列表渲染。这与更通用的 useTracker 截然不同,需要进行更多设置。一个显著的区别是你不应该调用 .fetch()useFind 要求其工厂返回一个 Mongo.Cursor 对象。如果你想有条件地设置游标,也可以返回 null

¥The useFind hook can substantially speed up the rendering (and rerendering) of lists coming from mongo queries (subscriptions). It does this by controlling document object references. By providing a highly tailored cursor management within the hook, using the Cursor.observe API, useFind carefully updates only the object references changed during a DDP update. This approach allows a tighter use of core React tools and philosophies to turbo charge your list renders. It is a very different approach from the more general purpose useTracker, and it requires a bit more set up. A notable difference is that you should NOT call .fetch(). useFind requires its factory to return a Mongo.Cursor object. You may also return null, if you want to conditionally set up the Cursor.

以下是代码示例:

¥Here is an example in code:

jsx
import React, { memo } from "react";
import { useFind } from "meteor/react-meteor-data";
import TestDocs from "/imports/api/collections/TestDocs";

// Memoize the list item
const ListItem = memo(({ doc }) => {
  return (
    <li>
      {doc.id},{doc.updated}
    </li>
  );
});

const Test = () => {
  const docs = useFind(() => TestDocs.find(), []);
  return (
    <ul>
      {docs.map((doc) => (
        <ListItem key={doc.id} doc={doc} />
      ))}
    </ul>
  );
};

// Later on, update a single document - notice only that single component is updated in the DOM
TestDocs.update({ id: 2 }, { $inc: { someProp: 1 } });

如果你想根据某些 props 配置或其他任何内容有条件地调用 find 方法,请从工厂返回 null

¥If you want to conditionally call the find method based on some props configuration or anything else, return null from the factory.

jsx
const docs = useFind(() => {
  if (props.skip) {
    return null;
  }
  return TestDocs.find();
}, []);

并发模式、暂停和错误边界

¥Concurrent Mode, Suspense and Error Boundaries

使用并发模式、Suspense 和错误边界时,需要牢记一些额外的注意事项,因为它们都可能导致 React 取消并丢弃(丢弃)渲染,包括响应式函数首次运行的结果。React 开发者经常强调的一点是,我们不应该在渲染方法或函数式组件中直接创建 "side-effects"。这样做有很多好处,包括允许 React 运行时取消渲染。限制副作用的使用,可使并发模式、暂停和错误边界等功能确定性地工作,而不会泄漏内存或创建恶意进程。由于这些原因,应注意避免响应式函数中出现副作用。(注意:此注意事项不适用于 Meteor 特有的副作用,例如订阅,因为这些副作用会在 useTracker 的计算被处理后自动清除。)

¥There are some additional considerations to keep in mind when using Concurrent Mode, Suspense and Error Boundaries, as each of these can cause React to cancel and discard (toss) a render, including the result of the first run of your reactive function. One of the things React developers often stress is that we should not create "side-effects" directly in the render method or in functional components. There are a number of good reasons for this, including allowing the React runtime to cancel renders. Limiting the use of side-effects allows features such as concurrent mode, suspense and error boundaries to work deterministically, without leaking memory or creating rogue processes. Care should be taken to avoid side effects in your reactive function for these reasons. (Note: this caution does not apply to Meteor specific side-effects like subscriptions, since those will be automatically cleaned up when useTracker's computation is disposed.)

理想情况下,诸如创建 Meteor 计算之类的副作用应该在 useEffect 中完成。但是,这对于 Meteor 来说是个问题,因为它在一次初始运行中混合了初始数据查询和设置用于监视这些数据源的计算。如果我们等到 useEffect 中执行此操作,最终将为每个使用 useTrackerwithTracker 的组件至少渲染两次(第一次渲染会使用 hack),或者在初始渲染时根本不运行,但仍然需要至少两次渲染,这会使 API 变得复杂。

¥Ideally, side-effects such as creating a Meteor computation would be done in useEffect. However, this is problematic for Meteor, which mixes an initial data query with setting up the computation to watch those data sources all in one initial run. If we wait to do that in useEffect, we'll end up rendering a minimum of 2 times (and using hacks for the first one) for every component which uses useTracker or withTracker, or not running at all in the initial render and still requiring a minimum of 2 renders, and complicating the API.

为了解决这个问题并保持快速运行,我们直接在渲染方法中创建计算,并在 useEffect 的后续版本中进行一系列检查,以确保计算保持最新且所有内容保持最新,同时确保在检测到渲染被丢弃时进行清理。在大多数情况下,这一切都应该是透明的。

¥To work around this and keep things running fast, we are creating the computation in the render method directly, and doing a number of checks later in useEffect to make sure we keep that computation fresh and everything up to date, while also making sure to clean things up if we detect the render has been tossed. For the most part, this should all be transparent.

需要理解的重要一点是,你的响应式函数可以在单个渲染中被多次调用,因为有时工作会被丢弃。此外,useTracker 在渲染提交之前(useEffect 运行之前)不会主动调用你的响应式函数。如果你的数据源变化特别快,这一点值得了解。通过这种可能非常短暂的暂停,可以进行检查以确保最终结果始终与响应式函数的当前状态保持同步。渲染完成 "committed" 并安装组件后,计算将继续运行,一切将按预期运行。

¥The important thing to understand is that your reactive function can be initially called more than once for a single render, because sometimes the work will be tossed. Additionally, useTracker will not call your reactive function reactively until the render is committed (until useEffect runs). If you have a particularly fast changing data source, this is worth understanding. With this very short possible suspension, there are checks in place to make sure the eventual result is always up to date with the current state of the reactive function. Once the render is "committed", and the component mounted, the computation is kept running, and everything will run as expected.

可暂停版本的钩子

¥Suspendable version of hooks

useTracker

这是 useTracker 版本,可与 React Suspense 一起使用。

¥This is a version of useTracker that can be used with React Suspense.

它的第一个参数需要一个键,用于标识计算并避免在组件重新渲染时重新创建它。

¥For its first argument, a key is necessary, witch is used to identify the computation and to avoid recreating it when the component is re-rendered.

它的第二个参数是一个可以异步和响应的函数,该参数的工作方式类似于不暂停的原始 useTracker

¥Its second argument is a function that can be async and reactive, this argument works similar to the original useTracker that does not suspend.

它的可选第三个参数,即依赖数组,其工作原理类似于不暂停的 useTracker,你可以传入一个此跟踪函数所依赖的变量数组。

¥For its optional third argument, the dependency array, works similar to the useTracker that does not suspend, you pass in an array of variables that this tracking function depends upon.

它的可选第四个参数,即选项对象,其工作原理类似于不暂停的 useTracker,你可以传入一个函数来设置何时应该跳过更新。

¥For its optional fourth argument, the options object, works similar to the useTracker that does not suspend, you pass in a function for when should skip the update.

jsx
import { useTracker } from "meteor/react-meteor-data/suspense";
import { useSubscribe } from "meteor/react-meteor-data/suspense";

function Tasks() {
  // this component will suspend
  useSubscribe("tasks");
  const { username } = useTracker("user", () => Meteor.user()); // Meteor.user() is async meteor 3.0
  const tasksByUser = useTracker(
    "tasksByUser",
    () =>
      TasksCollection.find(
        { username },
        { sort: { createdAt: -1 } }
      ).fetchAsync() // async call
  );

  // render the tasks
}

维护响应式上下文

¥Maintaining the reactive context

为了使用新的 Meteor 异步方法维护响应式上下文,我们使用新的 Tracker.withComputation API 来维护异步调用的响应式上下文。这是必要的,因为否则它只会被调用一次,并且计算将永远不会再次运行。这样,每次我们添加新的链接时,都会运行这个 useTracker。

¥To maintain a reactive context using the new Meteor Async methods, we are using the new Tracker.withComputation API to maintain the reactive context of an async call, this is needed because otherwise it would be only called once, and the computation would never run again, this way, every time we have a new Link being added, this useTracker is ran.

jsx
// needs Tracker.withComputation because otherwise it would be only called once, and the computation would never run again
const docs = useTracker("name", async (c) => {
  const placeholders = await fetch(
    "https://jsonplaceholder.typicode.com/todos"
  ).then((x) => x.json());
  console.log(placeholders);
  return await Tracker.withComputation(c, () =>
    LinksCollection.find().fetchAsync()
  );
});

经验法则是,如果你使用响应式函数(例如 find + fetchAsync),最好将其封装在 Tracker.withComputation 中,以确保计算保持活动状态。如果你只是调用不必要的函数(例如下面的函数),则该函数将始终保持响应状态。

¥A rule of thumb is that if you are using a reactive function for example find + fetchAsync, it is nice to wrap it inside Tracker.withComputation to make sure that the computation is kept alive, if you are just calling that function that is not necessary, like the one bellow, will be always reactive.

jsx
const docs = useTracker("name", () => LinksCollection.find().fetchAsync());

useSubscribe

这是 useSubscribe 版本,可与 React Suspense 一起使用。它与 useSubscribe 类似,它会抛出一个 Promise 并暂停渲染,直到 Promise 被解决。它不返回 Meteor 句柄来控制订阅。

¥This is a version of useSubscribe that can be used with React Suspense. It is similar to useSubscribe, it throws a promise and suspends the rendering until the promise is resolved. It does not return a Meteor Handle to control the subscription

jsx
import { useTracker } from "meteor/react-meteor-data/suspense";
import { useSubscribe } from "meteor/react-meteor-data/suspense";

function Tasks() {
  // this component will suspend
  useSubscribe("tasks");
  const { username } = useTracker("user", () => Meteor.user()); // Meteor.user() is async meteor 3.0
  const tasksByUser = useTracker(
    "tasksByUser",
    () =>
      TasksCollection.find(
        { username },
        { sort: { createdAt: -1 } }
      ).fetchAsync() // async call
  );

  // render the tasks
}

useFind

这是 useFind 版本,可与 React Suspense 一起使用。它与没有 Suspense 的 useFind 有一些不同,它抛出一个 Promise 并暂停渲染,直到 Promise 被解决。它会返回结果,并且是响应式的。你应该将要搜索的集合作为第一个参数传递,将包含参数的数组作为第二个参数传递,这些参数与你传递给集合的 find 方法的参数相同。第三个参数是可选的,它是一个依赖数组对象。它是为 SSR 设计的,如果你对 SSR 不感兴趣,则不必使用它。

¥This is a version of useFind that can be used with React Suspense. It has a few differences from the useFind without suspense, it throws a promise and suspends the rendering until the promise is resolved. It returns the result and it is reactive. You should pass as the first parameter the collection where is being searched upon and as the second parameter an array with the arguments, the same arguments that you would pass to the find method of the collection, third parameter is optional, and it is dependency array object. It's meant for the SSR, you don't have to use it if you're not interested in SSR.

jsx
import { useFind } from "meteor/react-meteor-data/suspense";
import { useSubscribe } from "meteor/react-meteor-data/suspense";

function Tasks() {
  // this component will suspend
  useSubscribe("tasks");
  const tasksByUser = useFind(TasksCollection, [
    {},
    { sort: { createdAt: -1 } },
  ]);

  // render the tasks
}

版本兼容性说明

¥Version compatibility notes

  • react-meteor-data v2.x :

    • useTracker 钩子 + withTracker HOC

      ¥useTracker hook + withTracker HOC

    • 需要 React ^16.8

      ¥Requires React ^16.8.

    • 此实现与 "React Suspense"、并发模式和错误边界兼容。

      ¥Implementation is compatible with "React Suspense", concurrent mode and error boundaries.

    • withTracker HOC 严格向后兼容 v1.x 中提供的 HOC,主版本号的变更仅仅是由于 React 版本要求的提升。提供兼容的 React 版本,现有使用 withTracker HOC 的 Meteor 应用可以自由地从 v1.x 升级到 v2.x,并兼容未来的 React 版本。

      ¥The withTracker HOC is strictly backwards-compatible with the one provided in v1.x, the major version number is only motivated by the bump of React version requirement. Provided a compatible React version, existing Meteor apps leveraging the withTracker HOC can freely upgrade from v1.x to v2.x, and gain compatibility with future React versions.

    • 之前弃用的 createContainer 函数已被移除。

      ¥The previously deprecated createContainer has been removed.

  • react-meteor-data v0.x :

    • withTracker HOC(+ createContainer,保留以与早期 v0.x 版本向后兼容)

      ¥withTracker HOC (+ createContainer, kept for backwards compatibility with early v0.x releases)

    • 需要 React ^15.3^16.0

      ¥Requires React ^15.3 or ^16.0.

    • 实现依赖于 React 生命周期方法 (componentWillMount / componentWillUpdate),这些方法属于 标记为在未来 React 版本中弃用 ("React Suspense")。

      ¥Implementation relies on React lifecycle methods (componentWillMount / componentWillUpdate) that are marked for deprecation in future React versions ("React Suspense").