You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chakra UI Textarea无法提交至React Hook Form问题求助

问题:React Hook Form 结合 Chakra UI Textarea 无法提交表单

我正在使用 Next.js(v13)、React(v18)、Chakra UI 和 React Hook Form。仅使用 Input 组件时表单能正常提交,但把 description 字段换成 Chakra UI 的 Textarea 组件后,表单能正常渲染却无法提交,控制台也没有报错,找不到问题原因。想问下能不能通过 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>
  )
}

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>
  )
}

Input 组件代码

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>
  )
}

问题原因与解决方法

问题出在你直接使用了 Chakra UI 的原生 Textarea 组件,但没有通过 React Hook Form 的 register 方法注册这个字段。表单无法获取到 description 的值,触发了 Yup 的必填校验却没显示错误(因为没关联表单状态),最终阻止了提交。

参考现有 Input 组件的封装方式,自己封装一个和 React Hook Form 关联的 Textarea 组件即可解决:

封装 Textarea 组件

import * as React from "react";
import { useFormContext } from "react-hook-form";
import type { TextareaProps } from "@chakra-ui/react";
import { FormControl, Textarea as CTextarea } from "@chakra-ui/react";

import { InputError } from "./InputError";
import { InputLabel } from "./InputLabel";

interface Props extends TextareaProps {
  name: string;
  label?: string;
  subLabel?: string;
}

export const Textarea = ({ 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} />
      <CTextarea {...register(props.name)} mb={0} {...props} />
      <InputError error={fieldError} />
    </FormControl>
  );
};

在表单中使用封装后的组件

替换原来的原生 Textarea 代码:

// 替换这两行
<Text mb='8px' fontWeight="medium" fontSize="sm" > Description</Text>
<Textarea name="description" rows={4} />

// 改为:
<Textarea name="description" label="Description" rows={4} />

这样处理后,Textarea 会和 React Hook Form 正确关联,表单能获取到字段值,通过校验后就能正常提交了。

内容的提问来源于stack exchange,提问作者Mel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 16:25:27