【问题标题】:Validation using Formik with Yup and React-select使用 Formik 和 Yup 和 React-select 进行验证
【发布时间】:2019-12-26 21:00:37
【问题描述】:

我正在使用 YupFormik 进行反应表单验证。 表单中有一个react-select 元素也需要验证。对于验证,我使用validationSchemaFormik 来验证值更改的表单。 我只需要选择字段的值作为字符串,因此不能获取完整的对象(键值)。 选择字段工作正常,但未清除验证错误消息。 问题是如何使用现有方法验证选择字段?

以下是最小的代码示例。

import ReactDOM from "react-dom";
import React, { useState } from "react";
import { Grid, TextField, Button } from "@material-ui/core";
import { Formik } from "formik";
import * as Yup from "yup";
import Select from "react-select";
import "./styles.css";

function App() {
  const [selectedYear, setSelectedYear] = useState("");

  const testSchema = Yup.object().shape({
    name: Yup.string().required("Enter Name"),
    year: Yup.string().required("Select Year")
  });

  const initialValues = {
    name: "",
    year: ""
  };

  const handleYearChange = (selectedYear, values) => {
    values.year = selectedYear.value;
    console.log(selectedYear);
    setSelectedYear(selectedYear);
  };

  const yearOptions = [
    { value: "1960", label: "1960" },
    { value: "1961", label: "1961" },
    { value: "1962", label: "1962" },
    { value: "1963", label: "1963" },
    { value: "1964", label: "1964" },
    { value: "1965", label: "1965" }
  ];

  return (
    <Formik validationSchema={testSchema} initialValues={initialValues}>
      {({
        handleChange,
        handleBlur,
        values,
        errors,
        touched,
        handleSubmit,
        setFieldTouched
      }) => {
        return (
          <>
            <Grid container spacing={2}>
              <Grid item md={12} xs={12}>
                <TextField
                  label="Name"
                  name="name"
                  margin="normal"
                  variant="outlined"
                  onChange={handleChange("name")}
                  style={{ width: "100%", zIndex: 0 }}
                  value={values.name}
                  onBlur={() => {
                    console.log("name");
                  }}
                />
                {errors.name}
              </Grid>

              <Grid item md={6} xs={12}>
                <Select
                  placeholder="Year"
                  value={selectedYear}
                  onChange={selectedOption => {
                    handleYearChange(selectedOption);
                    // handleYearChange(selectedOption, values);
                    // values.year = selectedOption.value;
                    console.log("values", values.year);
                    handleChange("year");
                  }}
                  isSearchable={true}
                  options={yearOptions}
                  name="year"
                  isLoading={false}
                  loadingMessage={() => "Fetching year"}
                  noOptionsMessage={() => "Year appears here"}
                />
                {errors.year}
              </Grid>
              <Grid
                item
                md={4}
                style={{ marginTop: "24px", marginBottom: "10px" }}
                xs={12}
              >
                <Button onClick={handleSubmit}>Save</Button>
              </Grid>
            </Grid>
          </>
        );
      }}
    </Formik>
  );
}

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

这里是代码框:

PS:我是 Reactjs 的新手。

【问题讨论】:

    标签: reactjs material-ui react-select formik yup


    【解决方案1】:

    我使用以下代码解决了我的问题。

    在顶部导入这个

    import Select from 'react-select';
    import { Formik, Form, Field } from 'formik';
    

    现在在 jsx 渲染部分编写这段代码

    <Formik
          initialValues={initialUserAddData}
          validationSchema={addUserValidationSchema}
          onSubmit={handleAddUser}
        >
          {({ errors }) => (
            <Form className="add-edit-user-form">
              <Field name="department">
                {({ field, form }) => (
                   <Select
                     className="select-wrap"
                     classNamePrefix="select-box"
                     options={department}
                     onChange={(selectedOption) =>
                         form.setFieldValue(
                           'department',
                           selectedOption.value,
                          )
                        }
                   />
                )}
             </Field>
             {errors.department && (
               <span className="error">{errors.department}</span>
             )}
           </Form>
          )}
     </Formik>
    

    它只是将react-selectformik 一起使用并在formik 验证中更新值的示例 您也可以使用 useFormik 钩子,但这是不同的方式

    【讨论】:

      【解决方案2】:

      我会使用 Formik select 而不是像这样反应选择:

          const initialValues = {
              name: "",
              year: ""
          };
      
          const testSchema = Yup.object().shape({
            name: Yup.string().required("Enter Name"),
            year: Yup.string().required("Select Year")
          });
      
          <Field as="select" name="year" id="year">
          <option value="" label="">
          Select Your Year{" "}
          </option>
          {yearOptions.map(item => 
             <option value={item.value} label={item.label}>{item.value}</option>
         )} 
          </Field>
      

      在选项数组上使用映射来制作选项

      【讨论】:

      • “使用选项数组上的映射来制作选项”也许添加它来说明使用它
      • 谢谢!其实我是stackoverflow的新贡献者,会更新我的答案
      【解决方案3】:

      简单的解决方案 :: 它适用于 任何其他输入类型的输入字段,例如 react-color,或 datepicker 或任何东西... 通过使用这个逻辑.. 你需要欺骗formik,它会认为这是一个事件,,,下面给出示例,,,,,这里-handleChange来自formik

      validationSchema = yup.object({
           year_value :yup.object().required('*year value is required.')
      })
      
      
      <Select 
          className="  "
          name="year_value"
          id="year_value"
          placeholder='Choose year value'
          value={values.year_value}
          onBlur={handleBlur}
          onChange={selectedOption => {
              let event = { target : { name:'year_value',value: selectedOption}}
              handleChange(event)
          }}
          onBlur={()=>{
            handleBlur({ target: {name:'year_value'} });
          }}
          options={yearOptions}
      />
      
      

      【讨论】:

        【解决方案4】:

        如果将来有人正在寻找解决方案,这里有一种替代方法可以从 react-select 获取选定值作为字符串 - 并且仍然让 Yup 对选择输入执行验证:

        使用 useField() 中的辅助函数,您可以设置“字段”的值、已触摸和错误状态。当您使用非输入元素(例如 react-select)时,useField() 非常有用。

        function FormikSelect(...props) {
          const [field, meta, helpers] = useField(name="mySelectInput"); // can pass 'props' into useField also, if 'props' contains a name attribute
          const { setValue, setTouched, setError } = helpers;
        
          const setFieldProps = (selectedOption) => {
              setValue(selectedOption.value) 
              setTouched(true)
              setError(undefined)
          }
        
          return (
                <Select onChange={selectedOption => setFieldProps(selectedOption)} />
          );
        };
        

        【讨论】:

        • 我的一个反馈是不要将这些分组在 onChange 中,并且至少打破 setTouched 方法调用并将其附加到 onBlur 道具,因为这就是感动事件的方式一般都会触发。
        【解决方案5】:

        改变

        handleChange("year")
        

        handleChange("year")(selectedOption.value);
        

        目前 Formik 值中的 year 字段未更新。 handleChange() 函数返回一个新函数,可以通过一个值调用该函数以更新 Formik 状态。

        发现这些东西的最简单方法是使用以下代码输出 Formik 道具:

        <pre>{JSON.stringify(props, null, 2)}</pre>
        

        See this sandbox 举个例子。在沙箱中,我完全消除了对自定义年份状态的需求。我建议只使用 Formik 状态来操作值。仅使用 Formik 状态,您可能需要在保存时仅提取年份部分,因为 react-select 默认使用完整对象。

        【讨论】:

        • 成功了,但是如果我使用handleChange("year")(selectedOption.value);,它不会在react-select 框中显示所选值,而是反映在values 对象中。但是,如果我这样做handleChange("year")(selectedOption);,那么它会反映react-select 上的选定选项,并且值对象似乎具有嵌套对象。 values 对象是否只有字符串值而不是嵌套对象?
        • react-select 包默认需要完整的对象。作者编写了一个单独的包以仅传递值部分,请查看:github.com/jossmac/react-select-simple-value
        • @jagsler,非常感谢您的决定,因为它帮助我解决了同样的问题。
        • 我不知道为什么,但是这个方法会抛出一个错误,说无法读取未定义的属性 'persist'
        猜你喜欢
        • 2019-09-12
        • 2019-10-09
        • 2020-01-01
        • 1970-01-01
        • 2020-07-05
        • 2021-06-27
        • 2020-05-10
        • 2020-12-06
        • 1970-01-01
        相关资源
        最近更新 更多