Material UI + React Form Hook + 多个复选框 + 默认选中

Man*_*nos 4 javascript forms checkbox material-ui react-hook-form

我正在尝试构建一个包含多个“分组”复选框的表单,使用react-form-hook Material UI.

这些复选框是从 HTTP 请求异步创建的。

我想提供一组对象 ID 作为默认值:

defaultValues: { boat_ids: trip?.boats.map(boat => boat.id.toString()) || [] }

此外,当我选择或取消选择一个复选框时,我想将对象ID添加/删除到react-hook-form.

IE。( boat_ids: [25, 29, 4])

我怎样才能做到这一点?

这是我试图重现该问题的示例

加分点,使用 Yup 验证最小选定复选框

boat_ids: Yup.array() .min(2, "")

use*_*242 7

Breaking API changes made in 6.X:

  • validation option has been changed to use a resolver function wrapper and a different configuration property name
    Note: Docs were just fixed for validationResolver->resolver, and code examples for validation in repo haven't been updated yet (still uses validationSchema for tests). It feels as if they aren't sure what they want to do with the code there, and it is in a state of limbo. I would avoid their Controller entirely until it settles down, or use Controller as a thin wrapper for your own form Controller HOC, which appears to be the direction they want to go in.
    see official sandbox demo and the unexpected behavior of "false" value as a string of the Checkbox for reference
import { yupResolver } from "@hookform/resolvers";
Run Code Online (Sandbox Code Playgroud)
  const { register, handleSubmit, control, getValues, setValue } = useForm({
    resolver: yupResolver(schema),
    defaultValues: Object.fromEntries(
      boats.map((boat, i) => [
        `boat_ids[${i}]`,
        preselectedBoats.some(p => p.id === boats[i].id)
      ])
    )
  });
Run Code Online (Sandbox Code Playgroud)
  • Controller no longer handles Checkbox natively (type="checkbox"), or to better put it, handles values incorrectly. It does not detect boolean values for checkboxes, and tries to cast it to a string value. You have a few choices:
  1. Don't use Controller. Use uncontrolled inputs
  2. Use the new render prop to use a custom render function for your Checkbox and add a setValue hook
  3. Use Controller like a form controller HOC and control all the inputs manually

Examples avoiding the use of Controller:
https://codesandbox.io/s/optimistic-paper-h39lq
https://codesandbox.io/s/silent-mountain-wdiov
Same as first original example but using yupResolver wrapper


Description for 5.X:

Here is a simplified example that doesn't require Controller. Uncontrolled is the recommendation in the docs. It is still recommended that you give each input its own name and transform/filter on the data to remove unchecked values, such as with yup and validatorSchema in the latter example, but for the purpose of your example, using the same name causes the values to be added to an array that fits your requirements.
https://codesandbox.io/s/practical-dijkstra-f1yox

Anyways, the problem is that your defaultValues doesn't match the structure of your checkboxes. It should be {[name]: boolean}, where names as generated is the literal string boat_ids[${boat.id}], until it passes through the uncontrolled form inputs which bunch up the values into one array. eg: form_input1[0] form_input1[1] emits form_input1 == [value1, value2]

https://codesandbox.io/s/determined-paper-qb0lf

构建defaultValues: { "boat_ids[0]": false, "boat_ids[1]": true ... }
控制器需要布尔值来切换复选框值,并将作为默认值提供给复选框。

 const { register, handleSubmit, control, getValues, setValue } = useForm({
    validationSchema: schema,
    defaultValues: Object.fromEntries(
      preselectedBoats.map(boat => [`boat_ids[${boat.id}]`, true])
    )
  });
Run Code Online (Sandbox Code Playgroud)

用于验证架构的架构,用于验证至少有 2 个选择,并将数据转换为所需的架构,然后再将其发送到 onSubmit。它过滤掉错误值,所以你得到一个字符串 id 数组:

  const schema = Yup.object().shape({
    boat_ids: Yup.array()
      .transform(function(o, obj) {
        return Object.keys(obj).filter(k => obj[k]);
      })
      .min(2, "")
  });
Run Code Online (Sandbox Code Playgroud)

  • 很好的解释。最好在答案本身中包含代码(至少是重要部分),以防 codeandbox 不可用。 (2认同)

Art*_*gan 5

我也一直在努力解决这个问题,这对我有用。

更新了 react-hook-form v6 的解决方案,也可以不用useState(下面的沙盒链接):

import React, { useState } from "react";
import { useForm, Controller } from "react-hook-form";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Checkbox from "@material-ui/core/Checkbox";

export default function CheckboxesGroup() {
  const defaultNames = ["bill", "Manos"];
  const { control, handleSubmit } = useForm({
    defaultValues: { names: defaultNames }
  });

  const [checkedValues, setCheckedValues] = useState(defaultNames);

  function handleSelect(checkedName) {
    const newNames = checkedValues?.includes(checkedName)
      ? checkedValues?.filter(name => name !== checkedName)
      : [...(checkedValues ?? []), checkedName];
    setCheckedValues(newNames);

    return newNames;
  }

  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      {["bill", "luo", "Manos", "user120242"].map(name => (
        <FormControlLabel
          control={
            <Controller
              name="names"
              render={({ onChange: onCheckChange }) => {
                return (
                  <Checkbox
                    checked={checkedValues.includes(name)}
                    onChange={() => onCheckChange(handleSelect(name))}
                  />
                );
              }}
              control={control}
            />
          }
          key={name}
          label={name}
        />
      ))}
      <button>Submit</button>
    </form>
  );
}


Run Code Online (Sandbox Code Playgroud)

Codesandbox 链接:https ://codesandbox.io/s/material-demo-54nvi ? file =/ demo.js

没有完成默认选定项目的另一种解决方案useStatehttps : //codesandbox.io/s/material-demo-bzj4i?file=/demo.js