react-hook-form:表单状态和输入状态之间双向映射的惯用方法
react-hook-form: idiomatic approach for two-way mapping between form state and input state
我目前正在为我的表单使用 Formik,但正在考虑切换到 react-hook-form。我担心的问题之一是输入的 DOM 状态与预期的 DOM 状态不同。一个示例是带有 type="number"
的输入,其 value
在 DOM 级别是一个字符串。所以我可能想将一个字符串映射到一个数字。在 Formik 中:
<input
type="number"
value={formikProps.values.myNumericField ?? ''}
onChange={(event) => {
formikProps.setFieldValue(
'myNumericField',
event.currentTarget.value === '' ? null : parseInt(event.currentTarget.value)
);
}}
/>
在 react-hook-form 中执行此操作的惯用方法是什么?
您可以改用受控输入并将其包装在 react-hook-form
的 Controller
中。
首先,创建您常用的受控输入,它至少需要 2 个道具,value
和 onChange
,并通知家长有关更改:
onst NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(({
onChange,
...inputProps
}, ref) => {
const handleChange = useCallback((e) => {
const { value } = e.target;
const parsedValue = parseInt(value, 10);
// If the value is not a number, we don't want to clear the input. Instead,
// just use the original string value and handle validation outside the input.
// You can be more strict about this by passing 0 or '' instead and changing
// the type attribute below to "number".
onChange(value === `${ parsedValue }` ? parsedValue : value);
}, [onChange]);
return (
<input
ref={ ref }
type="text"
onChange={ handleChange }
{ ...inputProps } />
);
});
要将此组件与 react-hook-form
一起使用,只需将其包装在 Controller
组件中,该组件将传递 onChange
、onBlur
、value
和 ref
到您的组件:
import ReactDOM from "react-dom";
import React, { useCallback } from "react";
import { useForm, Controller } from "react-hook-form";
const App: React.FC = () => {
const { handleSubmit, control, watch } = useForm();
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Controller
as={NumberInput}
control={control}
name="number"
defaultValue=""
/>
<pre>{ JSON.stringify(watch(), null, " ") }</pre>
<button type="submit">Submit</button>
</form>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
我目前正在为我的表单使用 Formik,但正在考虑切换到 react-hook-form。我担心的问题之一是输入的 DOM 状态与预期的 DOM 状态不同。一个示例是带有 type="number"
的输入,其 value
在 DOM 级别是一个字符串。所以我可能想将一个字符串映射到一个数字。在 Formik 中:
<input
type="number"
value={formikProps.values.myNumericField ?? ''}
onChange={(event) => {
formikProps.setFieldValue(
'myNumericField',
event.currentTarget.value === '' ? null : parseInt(event.currentTarget.value)
);
}}
/>
在 react-hook-form 中执行此操作的惯用方法是什么?
您可以改用受控输入并将其包装在 react-hook-form
的 Controller
中。
首先,创建您常用的受控输入,它至少需要 2 个道具,value
和 onChange
,并通知家长有关更改:
onst NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(({
onChange,
...inputProps
}, ref) => {
const handleChange = useCallback((e) => {
const { value } = e.target;
const parsedValue = parseInt(value, 10);
// If the value is not a number, we don't want to clear the input. Instead,
// just use the original string value and handle validation outside the input.
// You can be more strict about this by passing 0 or '' instead and changing
// the type attribute below to "number".
onChange(value === `${ parsedValue }` ? parsedValue : value);
}, [onChange]);
return (
<input
ref={ ref }
type="text"
onChange={ handleChange }
{ ...inputProps } />
);
});
要将此组件与 react-hook-form
一起使用,只需将其包装在 Controller
组件中,该组件将传递 onChange
、onBlur
、value
和 ref
到您的组件:
import ReactDOM from "react-dom";
import React, { useCallback } from "react";
import { useForm, Controller } from "react-hook-form";
const App: React.FC = () => {
const { handleSubmit, control, watch } = useForm();
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Controller
as={NumberInput}
control={control}
name="number"
defaultValue=""
/>
<pre>{ JSON.stringify(watch(), null, " ") }</pre>
<button type="submit">Submit</button>
</form>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);