React-hook-form useFieldArray 用于字符串数组而不是对象

问题描述 投票:0回答:2

我正在使用 useFieldArray 从后端 api 获取默认值。我的 categories 是一个字符串数组。但是,react-hook-form 仅支持对象数组。这是我的猫鼬的架构

 type BookDocument = Document & {
  title: string
  description: string
  categories: string[]
  language: string
  publicationYear: number
}

const bookSchema = new Schema(
  {
    title: { type: String, required: true },
    description: { type: String, required: true },
    categories: [{ type: String, requried: true }],
    language: { type: String, required: true },
    publicationYear: { type: Number, required: true },
  },
  { timestamps: true }
)

因此,从前端我必须修改我的表单如下:

type FormData = {
  title: string
  description: string
  categories: { category: string }[]
  language: string
  year: number
}

 const {
    handleSubmit,
    control,
    formState: { errors },
  } = useForm<FormData>({
    mode: 'onBlur',
    defaultValues: {
      title: book.title ?? '',
      description: book.description ?? '',
      categories:
        book.categories.map((elem) => {
          return { category: elem }
        }) ?? '',
      language: book.language ?? '',
      year: book.publicationYear ?? '',
    },
  })

问题出在调用api请求时。网络负载将如下所示,因此无法发送到后端

reactjs typescript mongoose-schema react-hook-form
2个回答
0
投票

您可以调用已解构为 const 的

handleSubmit
函数(位于代码片段中的
control
上方)。您可以选择在何处调用
handleSubmit
- 可能在表单上的按钮上 - 并且您可以调用回调,而不是仅仅调用
handleSubmit
,如下所示:

const handleFormSubmission = (data: any) => {
handleSubmit(wrappedSubmit)(data);

};


0
投票

有一个办法。查看我用来欺骗它返回平面数组的代码:

import {
  Box,
  Button,
  Grid,
  InputLabel,
  TextField,
  Typography,
} from '@mui/material';
import React from 'react';
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';

import InputErrorMessages from '../../../shared/InputErrorMessages';

export default function Variables() {
  const {
    control,
    formState: {
      errors,
    },
  } = useFormContext();
  const { fields, append, remove } = useFieldArray({
    name: 'variables',
    control,
  });

  return(
    <Grid item xs={12}>
      <Typography variant="h6">Variables</Typography>
      <Box my={2}>
        <InputErrorMessages name="variables" errors={errors} />
      </Box>
      <Grid container spacing={2}>
        { fields.map((unused, index) => (
          <Grid item key={index} xs={12}>
            <Controller
              name={`variables.${index}`}
              control={control}
              render={({ field }) => (
                <>
                  <InputLabel id="size">{`CRV${index+1} =`}</InputLabel>
                  <TextField 
                    onChange={field.onChange}
                    onBlur={field.onBlur}
                    inputRef={field.ref}
                    name={`variables.${index}.value`}
                    value={field.value.value || field.value}
                    sx={{ width: '100%' }}
                  />
                </>)}
            />
          </Grid>
        ))}
        <Grid item>
          <Button onClick={() => append('value')}>Add Variable</Button>
        </Grid>
        <Grid item>
          { fields.length > 0 && (<Button onClick={() => remove(fields.length - 1)}>Delete Variable</Button>)}
        </Grid>
      </Grid>
    </Grid>
  )
}

我欺骗了它,但没有使用

field
中的
fields.map
项目。相反,我使用 Controller 注册了自己的控件,因为我想控制字段的名称及其值。 IE。我想将该字段命名为
variables.${index}
而不是
variables.${index}.value
;如果您使用 useFieldArray() 返回的
field
项,后者将是自动的。

当你点击handleSubmit时,你会看到

variable
是一个平面数组。

但是,有一个小问题。如果您从后端加载带有字段的表单,它将期望

variable
是具有
value
属性的对象数组;它无法理解扁平的字符串数组。

但是,我再次能够欺骗它,因为我控制了该值。由此可见:

value={field.value.value || field.value}

基本上,如果对象上没有

value
属性,那么它一定是一个字符串;那么只需使用字符串即可。

希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.