官网地址:https://react-hook-form.com/
react-hook-form是专门为校验表单、提交表单设计的,使用起来比传统的onChange、setState要方便很多。
而且它进一步做了优化,减少了不必要的render
安装
npm install react-hook-form
使用
import React from "react";
import { useForm, SubmitHandler } from "react-hook-form";
type Inputs = {
example: string,
exampleRequired: string,
};
export default function App() {
const { register, handleSubmit, watch, formState: { errors } } = useForm<Inputs>();
const onSubmit: SubmitHandler<Inputs> = data => console.log(data);
console.log(watch("example")) // watch input value by passing the name of it
return (
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<form onSubmit={handleSubmit(onSubmit)}>
{/* register your input into the hook by invoking the "register" function */}
<input defaultValue="test" {...register("example")} />
{/* include validation with required or other standard HTML validation rules */}
<input {...register("exampleRequired", { required: true })} />
{/* errors will return when field validation fails */}
{errors.exampleRequired && <span>This field is required</span>}
<input type="submit" />
</form>
);
}
我们项目中的使用
export default function AddressForm({ className }: AddressFormProps): React.ReactElement {
const {
formState: { errors },
register,
} = useContext(UseFormContext) as UseFormReturn;
return (
<div className={classnames("space-y-6", className)}>
<Input
placeholder="Address Name (ex. home)*"
register={register("addressName", { required: "Address name is required" })}
{...useFormProps({ name: "addressName", errors })}
/>
<Input
placeholder="Street Name*"
register={register("streetName", { required: "Street Name is required" })}
{...useFormProps({ name: "streetName", errors })}
/>
<div className="grid grid-cols-2 gap-x-2 gap-y-6">
<Input
placeholder="Street Number*"
register={register("streetNumber", { required: "Street Number is required" })}
{...useFormProps({ name: "streetNumber", errors })}
/>
<Input
placeholder="Flat, Floor, Door"
register={register("flat", { required: "Flat, Floor, Door is required" })}
{...useFormProps({ name: "flat", errors })}
/>
<Input
placeholder="City*"
register={register("city", { required: "City is required" })}
{...useFormProps({ name: "city", errors })}
/>
<Select
options={states}
placeholder={stateSelectPlaceHolder}
register={register("state", { required: "State is required" })}
{...useFormProps({ name: "state", errors })}
/>
<Input
placeholder="PinCode*"
register={register("pinCode", { required: "Pin Code is required" })}
{...useFormProps({ name: "pinCode", errors })}
/>
<Input
placeholder="Country*"
register={register("Country", { required: "Country is required" })}
{...useFormProps({ name: "country", errors })}
/>
<Input
placeholder="LandMark*"
register={register("landMark", { required: "LandMark is required" })}
{...useFormProps({ name: "landMark", errors })}
/>
</div>
<Toggle label={<span className="body">Set as default address</span>} />
</div>
);
}
body={
<>
<UseFormContext.Provider value={useFormMethods}>
<AddressForm className="mt-4" />
</UseFormContext.Provider>
<div className="hidden md:block md:mt-10">
<CustomButton noMargin fullSize rounded primary label="SAVE" onClick={onSubmit} />
</div>
</>
}
const onSubmit = useMemo(
() =>
handleSubmit(async (data) => {
// TODO: Call API
// eslint-disable-next-line no-console
debugger;
console.log(data);
if (nextStepHref) {
await router.push(nextStepHref);
switch (nextStepHref.pathname) {
case pathnames.settingsAddressTab:
showNotifications({
type: "default",
title: "Address Changed",
message: "You have successfully changed your address.",
});
break;
default:
break;
}
}
}),
[handleSubmit, nextStepHref, router, showNotifications]
);
完全替代了原先需要在组件里面声明state来接受input的值。
监听功能
import React from "react";
import { useForm } from "react-hook-form";
function App() {
const { register, watch, formState: { errors }, handleSubmit } = useForm();
const watchShowAge = watch("showAge", false); // you can supply default value as second argument
const watchAllFields = watch(); // when pass nothing as argument, you are watching everything
const watchFields = watch(["showAge", "number"]); // you can also target specific fields by their names
const onSubmit = data => console.log(data);
return (
<>
<form onSubmit={handleSubmit(onSubmit)}>
<input type="checkbox" {...register("showAge")} />
{/* based on yes selection to display Age Input*/}
{watchShowAge && <input type="number" {...register("age", { min: 50 })} />}
<input type="submit" />
</form>
</>
);
}
单独组件监听
import React from "react";
import { useForm, useWatch } from "react-hook-form";
function IsolateReRender({ control }) {
const firstName = useWatch({
control,
name: 'firstName', // without supply name will watch the entire form, or ['firstName', 'lastName'] to watch both
defaultValue: 'default' // default value before the render
});
return <div>{firstName}</div>; // only re-render at the component level, when firstName changes
}
function App() {
const { register, control, handleSubmit } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log("data", data))}>
<input {...register("firstName")} />
<input {...register("last")} />
<IsolateReRender control={control} />
<input type="submit" />
</form>
);
默认值
很多时候,我们需要设置默认值,比如在编辑的时候,已经有原有的值了,这个时候怎么设置呢?
const useFormMethods = useForm<AddressInfo>({
defaultValues: {
streetAddress1: "dfsdds",
villageArea: "dfds",
houseNumber: "fsdf",
flat: "fdsdf",
townCity: "fdsd",
provinceState: "China",
pinCode: "dsffsd",
country: "dffds",
landMark: "fdsfds",
},
});
useFormContext 使用
表单在一个子组件里面,这时候就要用useFormContext了,
父组件:
import { useForm, FormProvider } from "react-hook-form";
const useFormMethods = useForm<AddressInfo>({
defaultValues: {
streetAddress1: "dfsdds",
villageArea: "dfds",
houseNumber: "fsdf",
flat: "fdsdf",
townCity: "fdsd",
provinceState: "China",
pinCode: "dsffsd",
country: "dffds",
landMark: "fdsfds",
},
});
<FormProvider {...useFormMethods}>
<AddressForm className="mt-4" onDefaultAddressChange={onDefaultAddressChange} />
</FormProvider>
通过FormProvider 把useFormMethods传递给子组件
子组件接收使用:
import { useFormContext } from "react-hook-form";
const {
formState: { errors },
register,
} = useFormContext();
<Input
placeholder="Address Name (ex. home)*"
register={register("streetAddress1", { required: "Address name is required" })}
{...useFormProps({ name: "streetAddress1", errors })}
/>
官方demo也挺好:
import React from "react";
import { useForm, FormProvider, useFormContext } from "react-hook-form";
export default function App() {
const methods = useForm();
const onSubmit = data => console.log(data);
return (
<FormProvider {...methods} > // pass all methods into the context
<form onSubmit={methods.handleSubmit(onSubmit)}>
<NestedInput />
<input type="submit" />
</form>
</FormProvider>
);
}
function NestedInput() {
const { register } = useFormContext(); // retrieve all hook methods
return <input {...register("test")} />;
}
官方demo地址 https://github.com/react-hook-form/react-hook-form/tree/master/examples
网友评论