我正在使用
Yup
和 Formik
进行反应表单验证。
表单中还有一个 react-select
元素也需要验证。为了进行验证,我使用 validationSchema
的 Formik
来验证值更改时的表单。
我只需要选择字段的值作为字符串,因此无法获取完整的对象(键值)。
选择字段工作正常,但验证错误消息未清除。
问题是如何使用现有方法验证选择字段?
下面是最小的代码示例。
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() 函数返回一个新函数,可以使用值调用该函数来更新 Formik 状态。
发现这些东西的最简单方法是使用以下代码输出 Formik 道具:
<pre>{JSON.stringify(props, null, 2)}</pre>
请参阅此沙箱以获取示例。在沙箱中,我完全消除了对自定义年份状态的需要。我建议仅使用 Formik 状态来操纵值。仅使用 Formik 状态,您在保存时可能只需要提取年份部分,因为反应选择默认使用完整对象。
你需要愚弄福米克,让他将这视为一个事件。
handleChange
这里来自福米克。这也适用于任何其他输入字段类型,例如 react-color
或日期选择器。
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}
/>
如果将来有人正在寻找解决方案,这里有一种替代方法,可以从react-select中以字符串形式获取所选值——并且仍然让Yup对选择输入执行验证:
使用 useField() 中的辅助函数,您可以设置“Field”的值、触摸和错误状态。每当您使用非输入元素(例如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)} />
);
};
我使用以下代码解决了我的问题。
在顶部导入它
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
钩子进行相同的操作,但这是不同的方式
我会使用 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>
使用选项数组上的地图来制作选项
以防有人仍在寻找答案。这会有帮助。
最初使用
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);
}}
/>
只需从 Formik 中销毁 setFieldValue,然后在选项的选择中设置值。这是例子:
<Select
withAsterisk
label="your_fileld_name_here"
placeholder="Select State"
data={['abc', 'xyz', 'asd', 'vbn']}
searchable
nothingFoundMessage="No State Found..."
name="state_select"
value={values.state_select}
onChange={(value) => **setFieldValue('your_fileld_name_here', value)}**
onBlur={handleBlur}
/>