使用 Formik 和 Yup 和 React-select 进行验证

Posted

技术标签:

【中文标题】使用 Formik 和 Yup 和 React-select 进行验证【英文标题】:Validation using Formik with Yup and 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 的新手。

【问题讨论】:

【参考方案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>

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

【讨论】:

“使用选项数组上的映射来制作选项”也许添加它来说明使用它 谢谢!其实我是***的新贡献者,会更新我的答案【参考方案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'

以上是关于使用 Formik 和 Yup 和 React-select 进行验证的主要内容,如果未能解决你的问题,请参考以下文章

使用 Formik 和 Yup 和 React-select 进行验证

使用 formik、yup 和 axios 去抖动

Formik 和 yup 验证不适用于所需

React JS:Yup & Formik 错误消息在提交时显示多次

Yup.mixed().test() 似乎破坏了 Formik 表单验证

Formik + Yup:如何在提交前立即验证表单?