You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

remix-validated-form重载默认值异常问题咨询

使用remix-validated-form时表单默认值更新异常的问题

我用remix-validated-form管理多字段表单,根据下拉框的change事件重载路由获取表单默认值,但表单无法正确设置新值——每次路由重载后,表单显示的都是上一次的旧默认值,而Remix原生Form则能正常工作。这是我的操作问题还是库的问题?我做了一个可复现的示例。

Loader代码

export const loader = async ({request}: LoaderArgs) => {
  const url = new URL(request.url);
  const value = url.searchParams.get('select') || '';

  const key = Math.random();
  let values = {select: '', fieldA: '', fieldB: '', key};

  if (value !== '') {
    values = {select: value, fieldA: `${value}-A`, fieldB: `${value}-B`, key};
  }

  return json({values});
};

路由代码

export default function RemixValidatedFormRoute() {
  const data = useLoaderData<typeof loader>();
  const navigate = useNavigate();

  const {getInputProps: selectProps} = useField('select', {formId: 'fT'});
  const {getInputProps: firstInputProps} = useField('fieldA', {formId: 'fT'});
  const {getInputProps: secondInputProps} = useField('fieldB', {formId: 'fT'});

  const validator = withZod(
    Z.object({select: Z.string(), fieldA: Z.string(), fieldB: Z.string()}),
  );

  return (
    <div>
      <ValidatedForm
        id="fT"
        validator={validator}
        defaultValues={data.values}
        key={data.values.key}
      >
        <select
          {...selectProps({
            id: 'select',
            className: 'select',
            onChange: event => {
              const value = event.target.value;
              navigate(`/test?select=${value}`, {replace: true});
            },
          })}
        >
          <option value=""> Select one</option>
          <option value="1"> First</option>
          <option value="2"> Second</option>
          <option value="3"> Third</option>
        </select>

        <input {...firstInputProps({ id: 'fieldA', className: 'fieldA' })} />
        <input {...secondInputProps({ id: 'fieldB', className: 'fieldB' })} />
      </ValidatedForm>
    </div>
  );
}

说明

  • 可测试Remix原生Form的正常工作情况
  • 复现步骤:
    1. 选择“First”→ 值已加载但下拉框未变更
    2. 选择“Third”→ 下拉框值更新为“First”
    3. 选择“Second”→ 所有输入框显示“Third”对应的值

问题原因与修复方案

核心原因

remix-validated-form的defaultValues仅在组件首次挂载时生效,后续defaultValues更新不会自动同步到表单状态。同时你手动处理下拉框onChange并触发导航,导致表单内部状态与loader返回的新值不同步,出现延迟更新的问题。

修复方案一:监听数据变化手动重置表单

通过useFormContext获取表单重置方法,监听loader返回值的变化,主动将表单状态重置为新的默认值:

export default function RemixValidatedFormRoute() {
  const data = useLoaderData<typeof loader>();
  const navigate = useNavigate();
  // 获取表单上下文的重置方法
  const { reset } = useFormContext({ formId: 'fT' });

  // 当loader返回的values变化时,重置表单
  useEffect(() => {
    reset(data.values);
  }, [data.values, reset]);

  const {getInputProps: selectProps} = useField('select', {formId: 'fT'});
  const {getInputProps: firstInputProps} = useField('fieldA', {formId: 'fT'});
  const {getInputProps: secondInputProps} = useField('fieldB', {formId: 'fT'});

  const validator = withZod(
    Z.object({select: Z.string(), fieldA: Z.string(), fieldB: Z.string()}),
  );

  return (
    <div>
      <ValidatedForm
        id="fT"
        validator={validator}
        defaultValues={data.values}
        // 用select值作为key,比随机数更稳定
        key={data.values.select}
      >
        <select
          {...selectProps({
            id: 'select',
            className: 'select',
            onChange: event => {
              const value = event.target.value;
              navigate(`/test?select=${value}`, {replace: true});
            },
          })}
        >
          <option value=""> Select one</option>
          <option value="1"> First</option>
          <option value="2"> Second</option>
          <option value="3"> Third</option>
        </select>

        <input {...firstInputProps({ id: 'fieldA', className: 'fieldA' })} />
        <input {...secondInputProps({ id: 'fieldB', className: 'fieldB' })} />
      </ValidatedForm>
    </div>
  );
}

修复方案二:改用表单提交触发路由更新

如果业务允许,移除手动导航逻辑,通过表单提交触发路由变化,让表单状态与loader返回值自动同步:

// 移除select的手动onChange,仅保留表单字段绑定
<select
  {...selectProps({
    id: 'select',
    className: 'select',
  })}
>
  {/* 选项不变 */}
</select>

// 给ValidatedForm添加action属性,通过表单提交触发路由action,再由action重定向到带参数的路由
// 同时调整loader和action逻辑,确保参数传递正确

内容的提问来源于stack exchange,提问作者Hernandcb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:00:04