前言
useFetcher
是 React Router
中一個強大的鉤子,用于在不觸發頁面導航的情況下執行數據加載(GET)或提交(POST)。
一、useFetcher 應用場景:
1、后臺數據預加載(如鼠標懸停時加載數據)
2、無刷新表單提交(如點贊、評論)
3、多步驟表單的局部提交
4、與當前頁面路由解耦的獨立數據操作
二、useFetcher 核心特性
非侵入式操作:不會影響當前路由或 URL。
狀態跟蹤:提供 state 屬性跟蹤操作狀態(idle/submitting/loading)
。
數據緩存:自動管理相同請求的緩存,避免重復提交。
多實例支持:可在同一頁面多次使用,獨立管理不同操作。
三、useFetcher 基本使用
3.1、 初始化 Fetcher
import { useFetcher } from "react-router-dom";function LikeButton() {const fetcher = useFetcher();return (<fetcher.Form method="post" action="/api/like"><button type="submit">{fetcher.state === "submitting" ? "點贊中..." : "點贊"}</button></fetcher.Form>);
}
3.2、useFetcher核心 API 與參數
useFetcher()
返回一個對象,包含以下屬性和方法:
屬性/方法
Form
: React 組件 用于 替代 <form>
,提交時不會觸發頁面導航
submit(data, options)
: 函數 用于 手動提交數據(支持 FormData/對象/URL
參數)
load(url)
: 函數 用于 手動觸發 GET 請求加載數據
data
: any 表示 最近一次成功操作返回的數據
state
: "idle"/"submitting"/"loading"
表示 當前操作狀態
四、useFetcher 完整案例:用戶評論功能
4.1、 組件代碼
function CommentSection({ postId }) {const fetcher = useFetcher();const [commentText, setCommentText] = useState("");// 顯示提交后的評論(包括樂觀更新)const comments = fetcher.data?.comments || [];return (<div><h3>評論列表</h3><ul>{comments.map((comment) => (<li key={comment.id}>{comment.text}</li>))}</ul><fetcher.Formmethod="post"action={`/posts/${postId}/comment`}onSubmit={() => setCommentText("")} // 清空輸入框><textareaname="text"value={commentText}onChange={(e) => setCommentText(e.target.value)}/><button type="submit" disabled={fetcher.state !== "idle"}>{fetcher.state === "submitting" ? "提交中..." : "發布評論"}</button></fetcher.Form>{/* 顯示錯誤信息 */}{fetcher.data?.error && (<div className="error">{fetcher.data.error}</div>)}</div>);
}
4.2、 后端路由處理(示例)
// 路由配置中的 action 函數
export async function commentAction({ request, params }) {const postId = params.postId;const formData = await request.formData();try {// 模擬 API 調用const response = await fetch(`/api/posts/${postId}/comment`, {method: "POST",body: JSON.stringify({ text: formData.get("text") }),});if (!response.ok) throw new Error("評論失敗");const result = await response.json();// 返回更新后的評論列表return { comments: result.comments };} catch (error) {return { error: error.message };}
}
五、useFetcher 高級用法:手動控制數據流
5.1、手動提交數據
function SearchBox() {const fetcher = useFetcher();const [query, setQuery] = useState("");// 輸入變化時自動搜索(防抖)useEffect(() => {const timeoutId = setTimeout(() => {if (query) {fetcher.load(`/api/search?q=${query}`);}}, 300);return () => clearTimeout(timeoutId);}, [query]);return (<div><inputtype="text"value={query}onChange={(e) => setQuery(e.target.value)}/>{/* 顯示搜索結果 */}{fetcher.data?.results?.map((result) => (<div key={result.id}>{result.name}</div>))}</div>);
}
5.2、處理文件上傳
function AvatarUpload() {const fetcher = useFetcher();const handleFileChange = (e) => {const file = e.target.files[0];const formData = new FormData();formData.append("avatar", file);// 手動提交 FormDatafetcher.submit(formData, {method: "post",action: "/api/upload-avatar",encType: "multipart/form-data",});};return (<div><input type="file" onChange={handleFileChange} />{fetcher.data?.url && (<img src={fetcher.data.url} alt="用戶頭像" />)}</div>);
}
六、useFetcher使用注意事項
6.1、路由配置要求
必須使用數據路由(通過 createBrowserRouter
創建路由)
提交的目標路由(action 路徑
)需要定義對應的 action 函數
6.2、性能優化
避免高頻調用 load/submit
(如搜索框需防抖)
對相同 URL 的請求,React Router
會自動去重
6.3、錯誤處理
通過 fetcher.data
接收 action
返回的錯誤信息
使用 try/catch
包裹異步操作并返回錯誤狀態
6.4、與全局狀態配合
如果需要更新全局數據(如用戶信息),結合 useRevalidator()
重新驗證路由加載器
七、useFetcher與普通表單提交的對比
總結:
我們可以用useFetcher
實現高度交互的 Web 應用,同時保持代碼的簡潔性和可維護性。
它是構建現代 SPA(單頁面應用) 中復雜交互(如即時保存、實時搜索)的理想工具。
如有錯誤之處,歡迎評論指正