雖然不可能完全消除應用程式中所有可能的競速條件,但 React Router 會自動處理網頁使用者介面中最常見的競速條件。
React Router 處理網路並發的方式,很大程度上受到網頁瀏覽器處理文件行為的啟發。
考慮點擊一個連結到新文件,然後在新頁面完成載入之前點擊另一個不同的連結。瀏覽器將會
相同的行為適用於表單提交。當一個待處理的表單提交被新的提交中斷時,第一個提交會被取消,而新的提交會立即被處理。
就像瀏覽器一樣,使用連結和表單提交的中斷導航將取消正在進行的資料請求,並立即處理新的事件。
Fetchers 稍微複雜一些,因為它們不像導航那樣是單例事件。Fetchers 無法中斷其他 fetcher 實例,但它們可以中斷自身,並且行為與其他所有情況相同:取消中斷的請求並立即處理新的請求。
然而,Fetchers 在重新驗證方面確實會相互交互。在 fetcher 的動作請求返回瀏覽器後,會發送所有頁面資料的重新驗證。這表示可能同時有多個重新驗證請求正在進行中。React Router 將提交所有「新鮮」的重新驗證回應,並取消任何過時的請求。過時的請求是指任何開始時間*早於*已返回的請求。
這種網路管理方式可以防止由網路競速條件引起的最常見 UI 錯誤。
由於網路是不可預測的,而且您的伺服器仍然會處理這些已取消的請求,因此您的後端可能仍然會遇到競速條件,並存在潛在的資料完整性問題。這些風險與使用純 HTML `<forms>` 的預設瀏覽器行為的風險相同,我們認為這些風險很低,並且超出 React Router 的範圍。
考慮建構一個預輸入下拉式方塊。當使用者輸入時,您會向伺服器發送請求。當他們輸入每個新字元時,您會發送一個新的請求。重要的是不要向使用者顯示不再在文字欄位中的值之結果。
當使用 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 上的待處理請求。這確保您永遠不會向使用者顯示針對不同輸入值的請求結果。