最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Reload data in Form after submission using Remix - Stack Overflow

programmeradmin0浏览0评论

I am using the Remix Form element to render my form containing various input fields. If there is a server-side validation error the text entered in the fields remains, which is as expected. However, when the form is successfully submitted I would like all the fields to refresh using the latest saved data from the db, which does not happen as they still contain what was previously entered.

A related issue is that when the form is submitted, contains password fields, and has validation issues, I would like those fields to be cleared similarly to what the standard form element does.

Is there a way of achieving this, or am I better off switching to form? I've also tried adding reloadDocument without any luck.

If I successfully submit this form, I would expect that the loader would be invoked again, producing an updated 10 char value. The actionData map would be null and so the input would display the abbreviated updated value. Instead, it displays the non-abbreviated value i.e. what the user entered and I have to navigate away and e back for it to properly pick it up.

Code:

export async function loader({ request }: LoaderArgs) {
  const value = await getValue();
  return {
    value: value.substring(0, 10)
  }
}

export async function action({ request }: ActionArgs) {
  const formData = await request.formData()
  const newValue = formData.get("newValue")

  if (isValid(newValue)) {
    return redirect("/update-value") // same page as we are already on
  }

  return {
    errors: {
      newValue: true
    },
    values: {
      newValue
    }
  }
}

export default function Page() {
  const loaderData = useLoaderData<typeof loader>()
  const actionData = useActionData<typeof action>()

  return (
    <Form method="POST">
      <input type="text" name="newValue" id="newValue" defaultValue={actionData?.errors.newValue ? actionData?.values.newValue : loaderData.value} />
      <button type="submit"/>
    </Form>
  )
}

I am using the Remix Form element to render my form containing various input fields. If there is a server-side validation error the text entered in the fields remains, which is as expected. However, when the form is successfully submitted I would like all the fields to refresh using the latest saved data from the db, which does not happen as they still contain what was previously entered.

A related issue is that when the form is submitted, contains password fields, and has validation issues, I would like those fields to be cleared similarly to what the standard form element does.

Is there a way of achieving this, or am I better off switching to form? I've also tried adding reloadDocument without any luck.

If I successfully submit this form, I would expect that the loader would be invoked again, producing an updated 10 char value. The actionData map would be null and so the input would display the abbreviated updated value. Instead, it displays the non-abbreviated value i.e. what the user entered and I have to navigate away and e back for it to properly pick it up.

Code:

export async function loader({ request }: LoaderArgs) {
  const value = await getValue();
  return {
    value: value.substring(0, 10)
  }
}

export async function action({ request }: ActionArgs) {
  const formData = await request.formData()
  const newValue = formData.get("newValue")

  if (isValid(newValue)) {
    return redirect("/update-value") // same page as we are already on
  }

  return {
    errors: {
      newValue: true
    },
    values: {
      newValue
    }
  }
}

export default function Page() {
  const loaderData = useLoaderData<typeof loader>()
  const actionData = useActionData<typeof action>()

  return (
    <Form method="POST">
      <input type="text" name="newValue" id="newValue" defaultValue={actionData?.errors.newValue ? actionData?.values.newValue : loaderData.value} />
      <button type="submit"/>
    </Form>
  )
}
Share Improve this question edited Jun 26, 2023 at 11:50 Anvar asked Jun 7, 2023 at 18:10 AnvarAnvar 1,2802 gold badges12 silver badges24 bronze badges 2
  • Can you provide some code? That would help me provide a better answer for your question. – Kiliman Commented Jun 8, 2023 at 14:17
  • Sorry for the delay, just added some code now. – Anvar Commented Jun 26, 2023 at 11:51
Add a ment  | 

1 Answer 1

Reset to default 5

The issue you're having is due to how React works. When Remix fetches data, either through navigation, form post, or revalidation, it simply updates its internal context with the returned data, and that triggers a re-render.

Remix does not unmount ponents on navigation, including <Outlet>. React handles that. Since you are redirecting to the same page, React is simply re-rendering the same ponents with the updated data.

The issue is that React will not update the defaultValue prop on form inputs or the initial state in useState. To get React to use the new value, you must tell React you want to unmount and remount the ponent with the latest data.

Typically you control this with the key prop. For example:

const location = useLocation()
return <Form key={location.key}>...</Form>

location.key will generate a unique key on each render, so this will ensure the ponent is unmounted when you redirect.

NOTE: since location.key updates on re-render, this will cause the form to remount on every re-render, not just navigation. This will also cause focus to be lost, so be aware of that.

Ideally, you would use a more stable key that only changes when the loader changes. This could be the actual URL: location.pathname. Since you're redirecting to the same route, you could return a timestamp from your loader and use that as a key.

Usually, this isn't too much of an issue if you redirect to a different route where the ponent tree differs from your original. Only when the trees are the same, do you have to deal with how React works. I hope this helps clarify things.

发布评论

评论列表(0)

  1. 暂无评论