🌊

Remix + conformでaction実行後にrevalidateされたloaderの値でFormを更新するための肝

2024/07/16に公開

背景

loaderでorderByを使って並び替えを行なっている場合、actionを使って保存処理を行った後、Formも並び替えられて欲しかった。

しかし、下記の対応をするまでは、値の更新はできてもdefaultValueは保持されるため、並べ替えは反映できなかった。

結論

idにloaderから取得したdataのJSONを入れ込むとidが都度変更されるため、再度defaultValueが設定され、並び替えがFormにも反映される。

import { useLoaderData, useActionData, useSubmit, Form } from '@remix-run/react';
import { useForm, getInputProps } from '@conform-to/react';

export default function TodoList() {
  const data = useLoaderData<typeof loader>();
  const actionData = useActionData<typeof action>();
  const submit = useSubmit();

  const [form, fields] = useForm({
    id: `todo-form-${JSON.stringify(data.todos)}`,
    onValidate({ formData }) {
      return parseWithZod(formData, { schema: todoSchema });
    },
    defaultValue: { todos: data.todos },
    lastResult: actionData?.result,
  });

  const todoFields = fields.todos.getFieldList();

  return (
    <div>
      <h1>TODOリスト</h1>
      <Form method="post" {...form.props}>
        <ul>
          {todoFields.map((todo, index) => (
            <li key={index}>
              <input type="text" {...getInputProps(todo.task, { type: 'text' })} />
              <input type="checkbox" {...getInputProps(todo.completed, { type: 'checkbox' })} />
              <button
                {...form.remove.getButtonProps({
                  name: fields.careerHistories.name,
                  index,
                })}
                onClick={() => {
                  if (confirm('削除してもよろしいですか?')) {
                    submit({ id: todo.id.value }, { method: 'delete' });
                  }
                }}
              >
                削除
              </button>
            </li>
          ))}
        </ul>
        <button type="submit">保存</button>
      </Form>
      <button {...form.insert.getButtonProps({
        name: fields.todos.name,
      })}>
        新しいTODOを追加
      </button>
    </div>
  );
}

あとがき

メモがてら急ぎ足で書いたので雑ですが、誰かの助けになれば幸いです。

Discussion