React Formik复选框组不会变成单个选中或未选中元素的数组

时间:2019-08-26 08:37:36

标签: javascript reactjs formik

我正在使用Formik在网站上创建表单。在这种形式下,我有一组标记,希望可以使用各个复选框对其进行检查,但是将它们保留在数组tags中。 Formik声称可以通过在Field元素上使用相同的name属性来做到这一点,但我无法使其正常工作。

我正在使用此code example作为参考。

这是我的代码:

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 个答案:

答案 0 :(得分:1)

使用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>
    )}
/>

Working sandbox


更新:

您也可以通过编写自己的组件来做到这一点。

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" />

答案 1 :(得分:1)

使用没有任何 Formik 特定组件的 Formik 2:

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 值中的标记。

Full working Sandbox example