简体   繁体   English

使用 object 作为 `react-hook-form` 中的值

[英]Using object as a value in `react-hook-form`

Description描述

I have a component that uses an object as a value.我有一个使用 object 作为值的组件。

I would like to use this component with react-hook-form我想将此组件与react-hook-form一起使用

The problem is that react-hook-form thinks that my object is a nested form control问题是react-hook-form认为我的 object 是一个嵌套的表单控件

Setup设置

This is just an example.这只是一个例子。

Range date picker is a common use case for such a behaviour范围日期选择器是此类行为的常见用例

Example codepen 代码笔示例

The value that the component accepts:组件接受的值:

type ComponentValue = {
  a: string;
  b: string;
}

The component:组件:

const Component = ({ value, onChange }: { value: ComponentValue, onChange: (value: ComponentValue) => void }) => {
  return (
    <input value={value.a} onChange={e => onChange({ a: e.target.value, b: (Math.random() * 100 | 0).toString() }) } />
  )
}

Form value表格值

type FormValues = {
  someField: ComponentValue;
  // other fields
};

Default values:默认值:

const defaultValues = {
  someField: {
    a: 'Default a',
    b: 'Default b'
  },
  // other fields
};

useForm usage: useForm用法:

const {
  register,
  handleSubmit,
  formState: { errors },
  control,
} = useForm<FormValues>({
  defaultValues,
});

The problem问题

Hovering over (or trying to use) errors reveals the type:将鼠标悬停在(或尝试使用) errors上会显示类型:

const errors: {
  someField?: {
    a?: FieldError | undefined;
    b?: FieldError | undefined;
  } | undefined;
  // other fields
}

But I would it to be:但我希望它是:

const errors: {
  someField?: FieldError | undefined;
  // other fields
}

Summary概括

Can I somehow force react-hook-form to treat my object as a value instead of a nested form field?我可以以某种方式强制react-hook-form将我的 object 视为一个值而不是嵌套的表单字段吗?

If you want to combine 2 inputs in a same component, you can try the approach with a controller.如果您想在同一个组件中组合 2 个输入,您可以尝试使用 controller 的方法。

export default function App() {
  const { control, handleSubmit, watch } = useForm({
    defaultValues: {
      travel: {
        from: "paris",
        to: "london"
      }
    }
  });

  const onSubmit = (data) => {
    console.log("dans onSubmit", JSON.stringify(data, null, 2));
  };

  return (
    <>
      <h1>Travel</h1>

      <form
        onSubmit={handleSubmit(onSubmit)}
        style={{ display: "flex", flexDirection: "column", maxWidth: 600 }}
        noValidate
      >
        <TravelPicker control={control} />

        <input type="submit" />
        <pre>{JSON.stringify(watch(), null, 2)}</pre>
      </form>
    </>
  );

The component have a control props, to be able to register the 2 inputs:该组件有一个控制道具,能够注册 2 个输入:

const TravelPicker = ({ control }) => {
  return (
    <>
      <label>
        From
        <Controller
          name="travel.from"
          control={control}
          render={({ field: { onChange, value, name } }) => (
            <input name={name} value={value} onChange={(e) => onChange(e)} />
          )}
        />
      </label>
      <label>
        To
        <Controller
          name="travel.to"
          control={control}
          render={({ field: { onChange, value, name } }) => (
            <input name={name} value={value} onChange={(e) => onChange(e)} />
          )}
        />
      </label>
    </>
  );
};

The errors object has then the same structure as the form inputs.错误 object 具有与表单输入相同的结构。

See this sandbox for a functional exemple.有关功能示例,请参阅此沙箱

The createor of RHF seems to indicate here that you can also have only one component for 2 inputs. RHF 的创建者似乎在这里表明您也可以只有一个组件用于 2 个输入。

You can use setValue and setError like below:您可以像下面这样使用setValuesetError

const {setValue, setError} = useForm();

// ... some where in your form
<input 
  type = "text"
  name = "from"
  onChange = {
    (event) => {
      const value = event.target.value;
      if(value === ""){
        setError("from", "This field is required");
      }else{
        setValue(`from[0]`, {
          "otherProperty" : "otherValue",
          "from_value": value, // this is your input value
        });
      }
    }
  }
/>

Probably you would be iterating through an array.可能你会遍历一个数组。 change static 0 with your index in setValue If not you may use object syntax like below:用你在setValue中的索引改变 static 0如果不是你可以使用 object 语法如下:

//....
setValue(`from.your_property_name`, {
    "otherProperty" : "otherValue",
    "from_value": value, // this is your input value
});

// ....

This won't cause re-render of component.这不会导致重新渲染组件。

More info in doc文档中的更多信息

NOTE: Please be respectful when commenting.注意:评论时请尊重。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM