form x Server Actions x useFormStateの探求
ここらへんを改めて理解する
ここに本格的にかいてあったはず
const initialState = { message: null, errors: {} };
const [state, dispatch] = useFormState(createInvoice, initialState);
reducerみたいな感じでactionとinitialStateを渡してstateとdispatchを生成する
zod側でエラーメッセージを管理する
const FormSchema = z.object({
id: z.string(),
customerId: z.string({
invalid_type_error: 'Please select a customer.',
}),
amount: z.coerce
.number()
.gt(0, { message: 'Please enter an amount greater than $0.' }),
status: z.enum(['pending', 'paid'], {
invalid_type_error: 'Please select an invoice status.',
}),
date: z.string(),
});
actionのinterfaceが変わる。第一引数がState
export async function createInvoice(prevState: State, formData: FormData) {
error.flatten()て何者だ
if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
message: 'Missing Fields. Failed to Create Invoice.',
};
}
こいつか
こうなるらしい
if (!result.success) {
console.log(result.error.flatten());
}
/*
{
formErrors: [],
fieldErrors: {
name: ['Expected string, received null'],
contactInfo: ['Invalid email']
},
}
*/
field名でそのエラーを取ってこれるっていうことか
だからこうすると。
<div id="customer-error" aria-live="polite" aria-atomic="true">
{state.errors?.customerId &&
state.errors.customerId.map((error: string) => (
<p className="mt-2 text-sm text-red-500" key={error}>
{error}
</p>
))}
</div>
完全に理解した気がする。
bindするときはbindしてから渡すし
const initialState = { message: null, errors: {} };
const updateInvoiceWithId = updateInvoice.bind(null, invoice.id);
const [state, dispatch] = useFormState(updateInvoiceWithId, initialState);
formStateの前にbinded argsがくる
export async function updateInvoice(
id: string,
prevState: State,
formData: FormData,
) {
きみ何者なん
The form state is the value returned by the action when the form was last submitted. If the form has not yet been submitted, it is the initial state that you pass.
form stateはactionの返り値。未actionならinitialState。
initialState: The value you want the state to be initially. It can be any serializable value. This argument is ignored after the action is first invoked.
Stateはシリアライズ可能な値
When used with a framework that supports React Server Components, useFormState lets you make forms interactive before JavaScript has executed on the client. When used without Server Components, it is equivalent to component local state.
どゆことやろか、わかる気がするけどわからん
actionのシグネチャ変わるのちょっとキモいけどな、Reducerと同じって考えたら許せるかな
サイズちょっと気になるな
ちなみに君は?
formの中で呼び出せば、直近のform submittionの状態を取ってこれるのか、簡単でつよいな。
const { pending, data, method, action } = useFormStatus();
例としてボタンの状態管理に呼ばれてる。いいね。
function Submit() {
const status = useFormStatus();
return <button disabled={status.pending}>Submit</button>
}
自前でlocal state作ってたのがなくなりそう。素晴らしい。