React Query and Forms
表單是許多 web 應用程式中更新資料的主要方式。我們用 React Query 不只拿資料(react query as a state manager),也會用來修改資料,所以一定會遇到要把這個強大的 async 狀態管理工具和表單整合的情境。
好消息是,其實表單本身沒什麼特別的:它就是一堆 html 元素,用來顯示資料。但當我們想要修改這些資料時,server state 跟 client state 的界線就會變得模糊,這也是複雜度的來源。
Server State vs. Client State
簡單回顧一下,Server State 是我們「不擁有」的狀態,通常是 async 的,只能看到上次抓到的快照。
Client State 則是前端完全掌控的狀態,通常是同步的,隨時都知道最新值。
如果我們顯示一個人員列表,這肯定是 server state。但如果點進去顯示細節、打算編輯,這時 server state 會變成 client state 嗎?還是混合體?
最簡單的做法
我之前寫過,不太建議把 state 從一個 state manager 複製到另一個(像是 putting props to useState 或 React Query 複製到 local state)。
但表單是個例外,只要你知道 tradeoff 並有意識地這麼做。大多數情況下,表單只需要把 server state 當作初始值。我們抓到 firstName、lastName,放進 form state,然後讓使用者編輯。
來看個例子:
// simple-form
function PersonDetail({ id }) {
const { data } = useQuery({
queryKey: ['person', id],
queryFn: () => fetchPerson(id),
})
const { register, handleSubmit } = useForm()
const { mutate } = useMutation({
mutationFn: (values) => updatePerson(values),
})
if (data) {
return (
<form onSubmit={handleSubmit(mutate)}>
<div>
<label htmlFor="firstName">First Name</label>
<input
{...register('firstName')}
defaultValue={data.firstName}
/>
</div>
<div>
<label htmlFor="lastName">Last Name</label>
<input
{...register('lastName')}
defaultValue={data.lastName}
/>
</div>
<input type="submit" />
</form>
)
}
return 'loading...'
}
這樣其實很好用——但有什麼 tradeoff?