竞争条件

竞争条件



虽然无法消除应用程序中所有可能的竞争条件,但 React Router 会自动处理 Web 用户界面中最常见的竞争条件。

浏览器行为

React Router 对网络并发的处理很大程度上受到了 Web 浏览器处理文档行为的启发。

想象一下,点击一个链接到一个新文档,然后在加载新页面完成之前又点击了另一个不同的链接。浏览器将会:

  1. 取消第一个请求
  2. 立即处理新的导航

同样的行为也适用于表单提交。当一个待处理的表单提交被一个新的提交中断时,第一个提交会被取消,并立即处理新的提交。

React Router 行为

与浏览器一样,被中断的链接导航和表单提交将取消正在进行中的数据请求,并立即处理新事件。

Fetcher 的情况稍微复杂一些,因为它们不像导航那样是单例事件。Fetcher 不能中断其他 fetcher 实例,但它们可以中断自身,其行为与其他情况相同:取消被中断的请求,并立即处理新的请求。

然而,在重新验证方面,Fetcher 之间会相互作用。当一个 fetcher 的 action 请求返回到浏览器后,会发送一个对所有页面数据的重新验证请求。这意味着多个重新验证请求可能同时在进行中。React Router 将提交所有“最新”的重新验证响应,并取消任何过时的请求。过时的请求是指任何比已返回的请求开始得 *更早* 的请求。

这种对网络的管理可以防止由网络竞争条件引起的最常见的 UI 错误。

由于网络是不可预测的,并且你的服务器仍然会处理这些被取消的请求,因此你的后端可能仍然会遇到竞争条件和潜在的数据完整性问题。这些风险与使用原生 HTML <form> 的默认浏览器行为的风险相同,我们认为这种风险较低,并且超出了 React Router 的范畴。

实际好处

考虑构建一个输入提示组合框(type-ahead combobox)。当用户输入时,你向服务器发送一个请求。当他们输入每个新字符时,你发送一个新的请求。重要的是不要向用户显示不再存在于文本字段中的值的搜索结果。

当使用 fetcher 时,这会自动为你管理。请看下面的伪代码:

// route("/city-search", "./search-cities.ts")
export async function loader({ request }) {
  const { searchParams } = new URL(request.url);
  return searchCities(searchParams.get("q"));
}
export function CitySearchCombobox() {
  const fetcher = useFetcher();

  return (
    <fetcher.Form action="/city-search">
      <Combobox aria-label="Cities">
        <ComboboxInput
          name="q"
          onChange={(event) =>
            // submit the form onChange to get the list of cities
            fetcher.submit(event.target.form)
          }
        />

        {fetcher.data ? (
          <ComboboxPopover className="shadow-popup">
            {fetcher.data.length > 0 ? (
              <ComboboxList>
                {fetcher.data.map((city) => (
                  <ComboboxOption
                    key={city.id}
                    value={city.name}
                  />
                ))}
              </ComboboxList>
            ) : (
              <span>No results found</span>
            )}
          </ComboboxPopover>
        ) : null}
      </Combobox>
    </fetcher.Form>
  );
}

fetcher.submit 的调用会自动取消该 fetcher 上的待处理请求。这可以确保你永远不会向用户显示针对不同输入值的请求结果。

文档和示例 CC 4.0
编辑