React Formik复选框组不会转换为选中或未选中的单独元素数组。

8

我正在使用 Formik 在网站上创建一个表单。在这个表单中,我有一组标签,我想要用单独的复选框来选择它们,但是将它们保留在数组中 tags。Formik声称可以通过在 Field 元素上使用相同的 name 属性来实现,但我无法让它工作。

我正在使用这个代码示例作为参考。

以下是我的代码:

import React from "react";
import ReactDOM from "react-dom";
import { Formik, Form, Field } from "formik";

import "./styles.css";

function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <ProjectsForm />
    </div>
  );
}

const ProjectsForm = props => (
  <Formik
    initialValues={{
      search: "",
      tags: []
    }}
    onSubmit={values => {
      console.log(values);
    }}
    validate={values => {
      console.log(values);
    }}
    validateOnChange={true}
  >
    {({ isSubmitting, getFieldProps, handleChange, handleBlur, values }) => (
      <Form>
        <Field type="text" name="search" />
        <label>
          <Field type="checkbox" name="tags" value="one" />
          One
        </label>
        <label>
          <Field type="checkbox" name="tags" value="two" />
          Two
        </label>
        <label>
          <Field type="checkbox" name="tags" value="three" />
          Three
        </label>
      </Form>
    )}
  </Formik>
);

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

另外在CodeSandbox上也有相关内容。

我期待通过console.log(values)显示类似以下的内容:

Object {search: "", tags: ['one', 'three']}

或者

Object {search: "", tags: ['one': true, 'two': false, 'three': true]}

希望我所遗漏的添加Formik复选框组功能的简单方法存在,因为它声称是可能的。

2个回答

23
使用FieldArray组件可以轻松实现。
将您的值放入一个数组中,就像这样:
const tagCollection = [
  { value: "one", label: "One" },
  { value: "two", label: "Two" },
  { value: "three", label: "Three" }
];

然后像这样使用 FieldArray

<FieldArray
    name="tags"
    render={arrayHelpers => (
        <div>
            {tagCollection.map(tag => (
                <label key={tag.value}>
                    <input
                        name="tags"
                        type="checkbox"
                        value={tag}
                        checked={values.tags.includes(tag.value)}
                        onChange={e => {
                          if (e.target.checked) {
                            arrayHelpers.push(tag.value);
                          } else {
                            const idx = values.tags.indexOf(tag.value);
                            arrayHelpers.remove(idx);
                          }
                        }}
                    />
                    <span>{tag.label}</span>
                </label>
            ))}
        </div>
    )}
/>

可工作的沙盒


更新:

您还可以通过编写自己的组件来实现此操作。

const MyCheckbox = ({ field, form, label, ...rest }) => {
  const { name, value: formikValue } = field;
  const { setFieldValue } = form;

  const handleChange = event => {
    const values = formikValue || [];
    const index = values.indexOf(rest.value);
    if (index === -1) {
      values.push(rest.value);
    } else {
      values.splice(index, 1);
    }
    setFieldValue(name, values);
  };

  return (
    <label>
      <input
        type="checkbox"
        onChange={handleChange}
        checked={formikValue.indexOf(rest.value) !== -1}
        {...rest}
      />
      <span>{label}</span>
    </label>
  );
};

// And using it like this:
<Field component={MyCheckbox} name="tags" value="one" label="One" />
<Field component={MyCheckbox} name="tags" value="two" label="Two" />
<Field component={MyCheckbox} name="tags" value="three" label="Three" />

3
是的,我也发现了这一点,但我只是想知道是否有更简单的方法,就像 Formik 在 GitHub 的示例中所声称的那样。 - niklasbuhl
好的,我也加了一种不同的方法。可能更好/更容易。 - Jap Mul
谢谢,这对我非常有效!之前我尝试像 Formik 的示例一样实现它,但从未成功过。感谢您解决了一个巨大的头痛问题! - displacedtexan
@JapMul 我该如何处理这些组输入的验证? - Ameer Hamza

7

使用Formik 2,无需任何特定于Formik的组件:

import React from "react";
import { useFormik } from "formik";

export default function App() {
  return <ProjectsForm></ProjectsForm>;
}

const tags = ["one", "two", "three"];

const ProjectsForm = () => {
  const formik = useFormik({
    enableReinitialize: true,
    initialValues: {
      tags: []
    },
    onSubmit: (values) => {
      console.log(values);
    }
  });

  const handleChange = (e) => {
    const { checked, name } = e.target;
    if (checked) {
      formik.setFieldValue("tags", [...formik.values.tags, name]);
    } else {
      formik.setFieldValue(
        "tags",
        formik.values.tags.filter((v) => v !== name)
      );
    }
  };

  return (
    <form onSubmit={formik.handleSubmit}>
      {tags.map((tag) => (
        <div key={tag}>
          <input
            id={tag}
            type="checkbox"
            name={tag}
            checked={formik.values.tags.includes(tag)}
            onChange={handleChange}
          />
          <label htmlFor={tag}>{tag}</label>
        </div>
      ))}
      <button type="submit">Submit</button>
    </form>
  );
};

我首先创建了一个简单的标签数组。

然后,我使用useFormik钩子将表单绑定到一组复选框。复选框是否被选中取决于它是否在标签数组中。 因此:formik.values.tags.includes(tag)

我创建了一个自定义的更改处理函数,根据复选框是否选中来设置或删除Formik值中的标签。

完整的工作示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接