v1 へのアップグレード
このガイドでは、 v1 で導入されたすべての変更点を説明し、既存のコードベースをアップグレードする方法をご案内します。
#最小限必要な React バージョン
Conform は現在、 Reactのバージョンが18以上である必要があります。もし古いバージョンの React を使用している場合は、まず React のバージョンをアップグレードする必要があります。
#conform
オブジェクトは削除されました
まず、すべてのヘルパーが改名され、個別にインポートできるようになりました:
conform.input
-> getInputPropsconform.select
-> getSelectPropsconform.textarea
-> getTextareaPropsconform.fieldset
-> getFieldsetPropsconform.collection
-> getCollectionProps
以前 conform.VALIDATION_UNDEFINED
および conform.VALIDATION_SKIPPED
を使用していた場合、それらは zod インテグレーション (@conform-to/zod
) に移されました。
conform.VALIDATION_SKIPPED
-> conformZodMessage.VALIDATION_SKIPPEDconform.VALIDATION_UNDEFINED
-> conformZodMessage.VALIDATION_UNDEFINED
conform.INTENT
はもはやエクスポートされていないことに注意してください。インテントボタンを設定する必要がある場合は、より良い型安全性のために zod の z.discriminatedUnion() と組み合わせて、それを intent (または好みの何か)と名付けることができます。
オプションに関してもいくつかの破壊的変更があります:
getInputProps
におけるtype
オプションが現在必須になりました。
1<input {...getInputProps(fields.title, { type: 'text' })} />
description
オプションはariaDescribedBy
に改名され、ブール値の代わりに文字列型( description 要素のid
)になりました。
1<input
2 {...getInputProps(fields.title, {
3 ariaDescribedBy: fields.title.descriptionId,
4 })}
5/>
#フォーム設定の変更点
まず、form.props
が削除されました。代わりに getFormProps() ヘルパーを使用できます。
1import { useForm, getFormProps } from '@conform-to/react';
2
3function Example() {
4 const [form] = useForm();
5
6 return <form {...getFormProps(form)} />;
7}
useFieldset
および useFieldList
フックは削除されました。代わりにフィールドメタデータ上で getFieldset()
または getFieldList()
メソッドを呼び出すことができます。
1function Example() {
2 const [form, fields] = useForm();
3
4 // Before: useFieldset(form.ref, fields.address)
5 const address = fields.address.getFieldset();
6 // Before: useFieldList(form.ref, fields.tasks)
7 const tasks = fields.tasks.getFieldList();
8
9 return (
10 <form>
11 <ul>
12 {tasks.map((task) => {
13 // ネストされたリストを持つ追加のコンポーネントを定義する必要はなくなりました。
14 // フィールドセットに直接アクセスできるようになったためです。
15 const taskFields = task.getFieldset();
16
17 return <li key={task.key}>{/* ... */}</li>;
18 })}
19 </ul>
20 </form>
21 );
22}
validate
と list
のエクスポートは、フォームメタデータオブジェクトに統合されました:
1function Example() {
2 const [form, fields] = useForm();
3 const tasks = fields.tasks.getFieldList();
4
5 return (
6 <form>
7 <ul>
8 {tasks.map((task) => {
9 return <li key={task.key}>{/* ... */}</li>;
10 })}
11 </ul>
12 <button {...form.insert.getButtonProps({ name: fields.tasks.name })}>
13 Add (Declarative API)
14 </button>
15 <button onClick={() => form.insert({ name: fields.tasks.name })}>
16 Add (Imperative API)
17 </button>
18 </form>
19 );
20}
以下に、すべての同等のメソッドを示します:
validate
->form.validate
list.insert
->form.insert
list.remove
->form.remove
list.reorder
->form.reorder
list.replace
->form.update
list.append
およびlist.prepend
は削除されました。代わりにform.insert
を使用できます。
#スキーマ・インテグレーション
混乱を避けるために、各統合における API を一意の名前に変更しました。こちらが同等のメソッドです:
@conform-to/zod
parse
-> parseWithZodgetFieldsetConstraint
-> getZodConstraint
@conform-to/yup
parse
-> parseWithYupgetFieldsetConstraint
-> getYupConstraint
#送信処理の改善
セットアップを簡素化するために、送信オブジェクトを再設計しました。
1export async function action({ request }: ActionArgs) {
2 const formData = await request.formData();
3 const submission = parseWithZod(formData, { schema });
4
5 /**
6 * 送信ステータスは「success」、「error」、または undefined のいずれかになります。
7 * ステータスが undefined の場合、送信が準備されていないことを意味します(つまり、 intent が submit ではありません)。
8 */
9 if (submission.status !== 'success') {
10 return json(submission.reply(), {
11 // また、ステータスを使用してHTTPステータスコードを決定することもできます。
12 status: submission.status === 'error' ? 400 : 200,
13 });
14 }
15
16 const result = await save(submission.value);
17
18 if (!result.successful) {
19 return json(
20 submission.reply({
21 // `reply` メソッドに追加のエラーを渡すこともできます。
22 formErrors: ['Submission failed'],
23 fieldErrors: {
24 address: ['Address is invalid'],
25 },
26
27 // or avoid sending the the field value back to client by specifying the field names
28 hideFields: ['password'],
29 }),
30 );
31 }
32
33 // `resetForm` オプションを使用して送信に応答します。
34 return json(submission.reply({ resetForm: true }));
35}
36
37export default function Example() {
38 const lastResult = useActionData<typeof action>();
39 const [form, fields] = useForm({
40 // 混乱を避けるために、 `lastSubmission` は `lastResult` に改名されました。
41 lastResult,
42 });
43
44 // フォームメタデータからも送信のステータスを確認できるようになりました。
45 console.log(form.status); // "success", "error" or undefined
46}
#useInputControl
フックを使用したインテグレーションがシンプルに
useInputEvent
フックは、いくつかの新機能を備えた useInputControl フックに置き換えられました。
もはや input 要素の ref を提供する必要はありません。 DOM から入力要素を探し出し、見つからない場合は自動で挿入します。
カスタム input を制御された input として統合するために
control.value
を使用し、control.change(value)
を通じて値の状態を更新できるようになりました。フォームがリセットされると、値もリセットされます。
1import { useForm, useInputControl } from '@conform-to/react';
2import { CustomSelect } from './some-ui-library';
3
4function Example() {
5 const [form, fields] = useForm();
6 const control = useInputControl(fields.title);
7
8 return (
9 <CustomSelect
10 name={fields.title.name}
11 value={control.value}
12 onChange={(e) => control.change(e.target.value)}
13 onFocus={control.focus}
14 onBlur={control.blur}
15 />
16 );
17}