I'm working with a react form validation using Yup
along with Formik
.
There is a react-select
element in the form which needs to be validated as well. For validation i'm making use of validationSchema
of Formik
to validate form on value change.
I need only value of the select field as a string so cant take the complete object (key-value).
The select field is working fine how ever the validation error message is not cleared.
The question is how can I validate the select field with existing approach?
Below is the minimal code sample.
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);
Here is the codesandbox :
PS: I'm new to Reactjs.
Change
handleChange("year")
To
handleChange("year")(selectedOption.value);
Currently the year
field in the Formik value isn't updated. The handleChange() function returns a new function that can be called with a value to update the Formik state.
Easiest way to spot these things is by outputting the Formik props with the following code:
<pre>{JSON.stringify(props, null, 2)}</pre>
See this sandbox for an example. In the sandbox I have completely removed the need for the custom year state. I'd recommend using only the Formik state to manipulate the values. Using only Formik state you will probably have to extract only the year part when saving, because react-select uses the complete object by default.