使用 React-Hook-Forms 将子组件(下拉)传递给父组件:ref 不是 prop,提交时不保存任何值

Passing a child component(drop down) to the parent component with React-Hook-Forms: ref is not a prop & no values saved when submitted

我将这个名为 Size 的下拉 (select) 组件作为子组件并嵌套在父组件中 useFieldArray 我每次提交它时都会收到警告,并且控制台中未显示任何值。发生了什么事,我该如何解决?

这些是错误:

Warning: Size: ref is not a prop. Trying to access it will result in undefined being returned. If you need to access the same value within the child component, you should pass it as a different prop.

Field is missing name attribute …

Link 到 codesandbox: https://codesandbox.io/s/react-hook-form-usefieldarray-nested-arrays-forked-vjwbp?file=/src/Drop_drowns/Size.js

Size.js

import { InputLabel, MenuItem, FormControl, Select } from "@mui/material";

const Size = ({ name, ref, defaultValue }) => {
  return (
    <FormControl fullWidth variant="filled">
      <InputLabel id="Size Label">Size</InputLabel>
      <Select
        labelId="Size"
        id="size"
        name={name}
        label="Product"
        ref={ref}
        defaultValue={defaultValue}
      >
        <MenuItem value="S">Small</MenuItem>
        <MenuItem value="M">Medium</MenuItem>
        <MenuItem value="L">Large</MenuItem>
      </Select>
    </FormControl>
  );
};

export default Size;

嵌套字段数组:

import React from "react";
import { useFieldArray } from "react-hook-form";
import Size from "./Drop_drowns/Size";
import { TextField } from "@mui/material";

export default ({ nestIndex, control, register }) => {
  const { fields, remove, append } = useFieldArray({
    control,
    name: `test[${nestIndex}].nestedArray`
  });

  return (
    <div>
      {fields.map((item, k) => {
        return (
          <div key={item.id} style={{ marginLeft: 20 }}>
            <label>Colors:</label>
            <Size
              name={`test[${nestIndex}].nestedArray[${k}].field1`}
              ref={register({ required: true })}
              defaultValue={item.field1}
              style={{ marginRight: "25px" }}
            />
            {/* <input
              name={`test[${nestIndex}].nestedArray[${k}].field1`}
              ref={register({ required: true })}
              defaultValue={item.field1}
              style={{ marginRight: "25px" }}
            /> */}

            <TextField
              name={`test[${nestIndex}].nestedArray[${k}].field2`}
              ref={register()}
              defaultValue={item.field2}
            />

            <TextField
              name={`test[${nestIndex}].nestedArray[${k}].field3`}
              ref={register()}
              defaultValue={item.field3}
            />
            <button type="button" onClick={() => remove(k)}>
              Delete Colors
            </button>
          </div>
        );
      })}

      <button
        type="button"
        onClick={() =>
          append({
            field1: "field1",
            field2: "field2"
          })
        }
      >
        Add Colors
      </button>

      <hr />
    </div>
  );
};

字段数组:

import React from "react";
import { useFieldArray } from "react-hook-form";
import NestedArray from "./nestedFieldArray";
import { TextField } from "@mui/material";

let renderCount = 0;

export default function Fields({ control, register, setValue, getValues }) {
  const { fields, append, remove, prepends } = useFieldArray({
    control,
    name: "test"
  });

  renderCount++;

  return (
    <>
      <ul>
        {fields.map((item, index) => {
          return (
            <li key={item.id}>
              <TextField
                name={`test[${index}].name`}
                ref={register()}
                defaultValue={item.name}
              />

              <button type="button" onClick={() => remove(index)}>
                Delete
              </button>
              <NestedArray nestIndex={index} {...{ control, register }} />
            </li>
          );
        })}
      </ul>

      <section>
        <button
          type="button"
          onClick={() => {
            append({ name: "append" });
          }}
        >
          Add product
        </button>

        {/* <button
          type="button"
          onClick={() => {
            setValue("test", [
              ...getValues().test,
              {
                name: "append",
                nestedArray: [{ field1: "append", field2: "append" }]
              }
            ]);
          }}
        >
          update product
        </button> */}
      </section>

      <span className="counter">Render Count: {renderCount}</span>
    </>
  );
}

index.js

import React from "react";
import { useForm } from "react-hook-form";
import FieldArray from "./fieldArray";
import ReactDOM from "react-dom";

import "./styles.css";

const defaultValues = {
  test: [
    {
      product: "",
      nestedArray: [{ field1: "", field2: "", field3: "" }]
    },
    {
      product: "",
      nestedArray: [{ field1: "", field2: "", field3: "" }]
    }
  ]
};

function App() {
  const {
    control,
    register,
    handleSubmit,
    getValues,
    errors,
    reset,
    setValue
  } = useForm({
    defaultValues
  });
  const onSubmit = (data) => console.log("data", data);

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <h1>Array of Array Fields</h1>
      <p>
        The following example demonstrate the ability of building nested array
        fields.
      </p>

      <FieldArray
        {...{ control, register, defaultValues, getValues, setValue, errors }}
      />

      <button type="button" onClick={() => reset(defaultValues)}>
        Reset
      </button>

      <input type="submit" />
    </form>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

您正在尝试将名为 ref 的道具传递给功能组件。您不能将 refs 传递给功能组件。另外,您要传递的不是参考。请参阅 https://reactjs.org/docs/refs-and-the-dom.html#adding-a-ref-to-a-dom-element 以了解我正在谈论的示例。如果您将道具 ref 重命名为 referencereferralreferenceMaterial 等,您将摆脱这个问题。沙盒控制台中的以下错误也会让您知道这一点。

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

只需将您的道具更改为不同的、更具描述性的名称,您就可以再次开展业务。

编辑: 还, 编辑: 另外,我看到您正在将方法 register 传递给 refer。我不确定您是否立即需要一个作为道具传递的结果。如果是这样,你很好。如果你需要传递函数,你必须用匿名函数包装它以确保它不会立即被调用:

<Element props={() => {register({ required: true })}} />

封装函数后,不会立即调用它。 当你传递寄存器时,你传递的是函数。 当您传递 register() 时,您传递的是返回的结果,因为该函数会立即被调用。 这都是关于括号的。如果有括号,它会立即被调用。