Mainly responsible for defining form submitting function, the type of form data, validation rule of each component, pass the props to component through form context provider
List of validation rules supported:
required
min
max
minLength
maxLength
pattern => regExp
validate => using self-defined function to validate
To support schema-based form validation with , , & , where you can pass your schema to as an optional config. It will validate your input data against the schema and return with either or a valid result.
import React from "react";
import { FormProvider, useForm } from "react-hook-form";
import { Form } from "react-aria-components";
import CustomTextField from "../forms/customTextField";
import CustomButton from "../forms/customButton";
import useLoginMutation from "../../hooks/login/useLoginMutation";
import { useNavigate } from "@tanstack/react-router";
import { zodResolver } from "@hookform/resolvers/zod";
import { LoginRequest, loginRequestSchema } from "../../types/login";
const defaultFormValues: LoginRequest = {
email: "",
password: "",
};
const Login = () => {
const { mutateAsync } = useLoginMutation();
const navigate = useNavigate();
const methods = useForm({
defaultValues: defaultFormValues,
resolver: zodResolver(loginRequestSchema),
});
const { handleSubmit, setError } = methods;
const onSubmit = async (data: LoginRequest) => {
try {
const user = await mutateAsync(data);
localStorage.setItem("user", user.id.toString());
navigate({ to: "/" });
} catch (err) {
if (err instanceof Error) {
// set back the error to the field
setError("email", { message: err.message });
}
}
}
// to have side effect when failed to submit
const onError = (input: unknown) => {
console.log(input);
};
return (
<FormProvider {...methods}>
<Form
className="h-full flex flex-col items-center justify-center gap-2"
onSubmit={(e) => {
e.preventDefault();
// for handle submit, the validation will be triggered when the data is
// firstly submitted or changed
handleSubmit(onSubmit, onError)();
}}
>
<CustomTextField
name="email"
rules={{
required: true,
}}
label={"Email"}
/>
<CustomTextField
name="password"
type="password"
rules={{ required: true }}
label={"Password"}
/>
<CustomButton label="Login" type="submit" className="mt-5" />
</Form>
</FormProvider>
);
};
export default Login;
Component
Component is mainly responsible to handle field status correctly and the change behaviour
controlis passed into component with provider by default and linked with the parent form, so that the component becomes controllable
useControllerreturn the field status (isDirty, error) and on change method, etc