TodoEditコンポーネントがちょっとゴチャゴチャしてきたので整理します。
カスタムフックの作成
TodoEditで利用しているHookをカスタムフックにして、src/hooks/todo.tsに追い出します。
import { createTodoSchema } from "../schema/todo";
import { trpc } from "../utils/trpc";
import { useForm, zodResolver } from "@mantine/form";
import { useEffect } from "react";
import { type EditingTodo } from "../types/todo";
const useTodoEdit = (editingTodo: EditingTodo) => {
const utils = trpc.useContext();
const form = useForm({
initialValues: {
id: null as number | null,
title: "",
description: "",
},
validate: zodResolver(createTodoSchema),
});
useEffect(() => {
form.setValues(editingTodo);
}, [editingTodo]);
const createTodo = trpc.todo.create.useMutation({
onSettled: () => {
utils.todo.getAll.invalidate();
},
});
const updateTodo = trpc.todo.update.useMutation({
onSettled: () => {
utils.todo.getAll.invalidate();
},
});
return { form, createTodo, updateTodo };
};
export default useTodoEdit;
Updateに必要なTodoの情報をTodoEdit内部で取得する
Updateに必要なTodoの情報を、TodoEditにprops経由で伝えていますがちょっと微妙な気がします。
たまたま今回はTodo一覧にUpdateに必要なTodoの情報がすべてそろっていましたが、いつもそうとは限りません。
また、Updateに必要なTodoの情報が変化したとき、TodoEdit内部だけでなく、利用側も変更が必要です。
TodoEditに渡す情報は必要最低限(Todoのid)で、必要な情報はTodoEdit内部で取得したほうがよいでしょう。
というわけで、propsで渡されたidからTodoデータをtrpcでとってきて、そのデータが更新されたらsetValuesを呼び出すことにします。
@@ -14,9 +14,15 @@ const useTodoEdit = (editingTodo: EditingTodo) => {
},
validate: zodResolver(createTodoSchema),
});
+ const { data } = trpc.todo.get.useQuery(
+ { id: editingTodoId as number },
+ { enabled: editingTodoId != null }
+ );
useEffect(() => {
- form.setValues(editingTodo);
- }, [editingTodo]);
+ if (data) {
+ form.setValues(data);
+ }
+ }, [data?.id]);
最初、editingTodoIdがnullだったらuseQueryを実行してsetValueを実行しようとしていたのですが、hooksをif分内で使用してはいけないという制約があるので、うまくいきませんでした。最終的にTanstack queryにenableオプションというのが用意されていたので、editingTodoIdがnullでない時だけQueryを実行するように変更しました。
ここまでの変更は以下の通りです。