使用 Formik 与 Yup 和 React-select 进行验证
Validation using Formik with Yup and React-select
我正在使用 Yup
和 Formik
进行 React 表单验证。
表单中还有一个 react-select
元素也需要验证。为了进行验证,我使用 validationSchema
of Formik
来验证值更改时的表单。
我只需要 select 字段的值作为字符串,因此不能获取完整的对象(键值)。
select 字段工作正常,但未清除验证错误消息。
问题是如何使用现有方法验证 select 字段?
下面是最小的代码示例。
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 的新手。
改变
handleChange("year")
到
handleChange("year")(selectedOption.value);
目前 Formik 值中的 year
字段未更新。 handleChange() 函数 returns 一个新函数,可以用一个值调用来更新 Formik 状态。
发现这些东西的最简单方法是使用以下代码输出 Formik 道具:
<pre>{JSON.stringify(props, null, 2)}</pre>
See this sandbox 举个例子。在沙盒中,我已经完全消除了对自定义年份状态的需求。我建议仅使用 Formik 状态来操纵这些值。仅使用 Formik 状态,您在保存时可能只需要提取年份部分,因为 react-select 默认使用完整对象。
以防将来有人正在寻找解决方案,这里有另一种方法可以从 react-select 中获取 selected 值作为字符串——并且仍然让 Yup 执行select 输入的验证:
使用 useField() 的辅助函数,您可以设置 "Field" 的值、触摸和错误状态。 useField() 在您处理非输入元素时很有用,例如 react-select.
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)} />
);
};
简单的解决方案 :: 它有效,,,,,甚至对于 任何其他输入类型 的输入字段,如 react-color, 或日期选择器或任何东西... 通过使用此逻辑.. 你需要愚弄 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}
/>
我会使用 Formik select 而不是像这样反应 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>
在选项数组上使用映射来制作选项
我使用以下代码解决了我的问题。
在顶部导入这个
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-select
与 formik
一起使用并更新 formik 验证中的值的示例
您也可以使用 useFormik
挂钩,但这是不同的方式
以防有人还在寻找答案。这会有所帮助。
最初使用 Select
组件创建自定义组件。
import Select from "react-select";
export default function CustomSelect({ onChange, options, value, name, className = "" }) {
const defaultValue = (options, value) => {
return options ? options.find((option) => option.value === value) : "";
};
return (
<div>
<Select
className={className}
name={name}
value={defaultValue(options, value)}
onChange={(value) => {
onChange(value);
}}
options={options}
/>
</div>
);
}
导入自定义组件,使用如下。确保使用 formik 道具中的 setFieldTouched
和 setFieldValue
来设置和验证表单。
<CustomSelect
name="name"
value={"value"}
options={options}
onChange={(option) => {
setFieldTouched("name", true);
setFieldValue("name", option.value);
}}
/>
我正在使用 Yup
和 Formik
进行 React 表单验证。
表单中还有一个 react-select
元素也需要验证。为了进行验证,我使用 validationSchema
of Formik
来验证值更改时的表单。
我只需要 select 字段的值作为字符串,因此不能获取完整的对象(键值)。
select 字段工作正常,但未清除验证错误消息。
问题是如何使用现有方法验证 select 字段?
下面是最小的代码示例。
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 的新手。
改变
handleChange("year")
到
handleChange("year")(selectedOption.value);
目前 Formik 值中的 year
字段未更新。 handleChange() 函数 returns 一个新函数,可以用一个值调用来更新 Formik 状态。
发现这些东西的最简单方法是使用以下代码输出 Formik 道具:
<pre>{JSON.stringify(props, null, 2)}</pre>
See this sandbox 举个例子。在沙盒中,我已经完全消除了对自定义年份状态的需求。我建议仅使用 Formik 状态来操纵这些值。仅使用 Formik 状态,您在保存时可能只需要提取年份部分,因为 react-select 默认使用完整对象。
以防将来有人正在寻找解决方案,这里有另一种方法可以从 react-select 中获取 selected 值作为字符串——并且仍然让 Yup 执行select 输入的验证:
使用 useField() 的辅助函数,您可以设置 "Field" 的值、触摸和错误状态。 useField() 在您处理非输入元素时很有用,例如 react-select.
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)} />
);
};
简单的解决方案 :: 它有效,,,,,甚至对于 任何其他输入类型 的输入字段,如 react-color, 或日期选择器或任何东西... 通过使用此逻辑.. 你需要愚弄 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}
/>
我会使用 Formik select 而不是像这样反应 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>
在选项数组上使用映射来制作选项
我使用以下代码解决了我的问题。
在顶部导入这个
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-select
与 formik
一起使用并更新 formik 验证中的值的示例
您也可以使用 useFormik
挂钩,但这是不同的方式
以防有人还在寻找答案。这会有所帮助。
最初使用 Select
组件创建自定义组件。
import Select from "react-select";
export default function CustomSelect({ onChange, options, value, name, className = "" }) {
const defaultValue = (options, value) => {
return options ? options.find((option) => option.value === value) : "";
};
return (
<div>
<Select
className={className}
name={name}
value={defaultValue(options, value)}
onChange={(value) => {
onChange(value);
}}
options={options}
/>
</div>
);
}
导入自定义组件,使用如下。确保使用 formik 道具中的 setFieldTouched
和 setFieldValue
来设置和验证表单。
<CustomSelect
name="name"
value={"value"}
options={options}
onChange={(option) => {
setFieldTouched("name", true);
setFieldValue("name", option.value);
}}
/>