我正在使用 nextjs (v13)、react (v18) chakraUI 和 react hook 形式。
如果我(仅)使用输入,我可以提交此表单。如果我将描述字段更改为文本区域(来自 ChakraUI),表单会显示在页面上,但不会提交。我在控制台中没有收到任何错误 - 我看不出是什么导致了这个问题。
是否可以通过 react-hook-form 从 Textarea 提交数据?
import * as React from "react"
import { gql } from "@apollo/client"
import { Button, Stack, Textarea, Text } from "@chakra-ui/react"
import { useRouter } from "next/router"
import { useCreateIssueGroupMutation } from "lib/graphql"
import { useForm } from "lib/hooks/useForm"
import Yup from "lib/yup"
import { ButtonGroup } from "./ButtonGroup"
import { Form } from "./Form"
import { FormError } from "./FormError"
import { Input } from "./Input"
import { Modal } from "antd"
const _ = gql`
mutation CreateIssueGroup($data: IssueGroupInput!) {
createIssueGroup(data: $data) {
id
}
}
`
interface Props {
onClose: () => void
}
const IssueGroupSchema = Yup.object().shape({
title: Yup.string().required(),
description: Yup.string().required(),
})
export function AdminCreateIssueGroupForm(props: Props) {
const router = useRouter()
const [createIssueGroup] = useCreateIssueGroupMutation()
const defaultValues = {
title: "",
description: "",
}
const form = useForm({ defaultValues, schema: IssueGroupSchema })
const handleSubmit = (data: Yup.InferType<typeof IssueGroupSchema>) => {
return form.handler(() => createIssueGroup({ variables: { data: { ...data } } }), {
onSuccess: (res, toast) => {
toast({ description: "Issue group created" })
form.reset()
props.onClose()
},
})
}
return (
<Form {...form} onSubmit={handleSubmit}>
<Stack>
<Input name="title" label="Title" />
// this input works and allows me to submit the form
{/* <Input name="description" label="Description" /> */}
// the next 2 lines do not work. The page renders but the form does not submit
<Text mb='8px' fontWeight="medium" fontSize="sm" > Description</Text>
<Textarea name="description" rows={4} />
<FormError />
<ButtonGroup>
<Button onClick={props.onClose}>Cancel</Button>
<Button
type="submit"
isLoading={form.formState.isSubmitting}
isDisabled={form.formState.isSubmitting}
color="brand.white"
fontWeight="normal"
backgroundColor="brand.orange"
_hover={{
backgroundColor: "brand.green",
color: "brand.white",
}}
>
Create
</Button>
</ButtonGroup>
</Stack>
</Form>
)
}
我的表单组件有:
import * as React from "react"
import type { FieldValues, UseFormReturn } from "react-hook-form"
import { FormProvider, useFormContext } from "react-hook-form"
import { Box } from "@chakra-ui/react"
import * as Sentry from "@sentry/nextjs"
import { useToast } from "lib/hooks/useToast"
interface FormContainerProps {
onSubmit?: (values: any) => Promise<any> | any
onBlur?: (values: any) => Promise<any> | any
}
const FormContainer: React.FC<FormContainerProps> = (props) => {
const toast = useToast()
const { handleSubmit } = useFormContext()
const onSubmit = async (values: any) => {
try {
if (props.onBlur) {
return await props.onBlur(values)
}
if (props.onSubmit) {
return await props.onSubmit(values)
}
} catch (e) {
console.log(e)
Sentry.captureException(e)
toast({
title: "Application error",
description: "Something went wrong. We have been notified!",
status: "error",
})
return
}
}
return (
<Box
as="form"
w="100%"
{...(props.onSubmit && { onSubmit: handleSubmit(onSubmit) })}
{...(props.onBlur && { onBlur: handleSubmit(onSubmit) })}
>
{props.children}
</Box>
)
}
interface Props<T extends FieldValues> extends UseFormReturn<T>, FormContainerProps {
children: React.ReactNode
isDisabled?: boolean
}
export function Form<T extends FieldValues>({ onSubmit, onBlur, isDisabled, ...props }: Props<T>) {
return (
<FormProvider {...props}>
<fieldset disabled={isDisabled}>
<FormContainer {...{ onSubmit, onBlur }}>{props.children}</FormContainer>
</fieldset>
</FormProvider>
)
}
输入有:
import * as React from "react"
import { useFormContext } from "react-hook-form"
import type { InputProps } from "@chakra-ui/react";
import { FormControl, Input as CInput } from "@chakra-ui/react"
import { InputError } from "./InputError"
import { InputLabel } from "./InputLabel"
interface Props extends InputProps {
name: string
label?: string
subLabel?: string
}
export const Input = ({ label, subLabel, ...props }: Props) => {
const {
register,
formState: { errors },
} = useFormContext()
const fieldError = errors?.[props.name]
return (
<FormControl isInvalid={!!fieldError} isRequired={props.isRequired}>
<InputLabel label={label} subLabel={subLabel} name={props.name} />
<CInput {...register(props.name)} mb={0} {...props} />
<InputError error={fieldError} />
</FormControl>
)
}
最佳答案
每个连接到 React Hook Form 的表单组件都需要接收一个 register
或被一个 Controller
组件包裹。如您所述,您的输入组件通过 useFormContext
接收此信息:
<CInput {...register(props.name)} mb={0} {...props} />
但是,TextArea
组件不会从 Hook Form 接收任何信息,在这种情况下,您需要使用相同的 register('')
。
这个实现的一个例子(live on CodeSandbox):
function App() {
const { register, handleSubmit } = useForm({
defaultValues: {
title: "",
description: ""
}
});
return (
<>
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Heading>Welcome to Chakra + TS</Heading>
<p>Title</p>
<Input {...register("title")} />
<p>Description</p>
<Textarea {...register("description")} />
<Button type="submit">Submit</Button>
</form>
</>
);
}
有用的链接:
关于reactjs - Chakra UI 中的文本区域输入字段不会提交以 react Hook 形式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74765126/