问题
React-Select with Formik is not loading the selected value in select componenet but I'm able to get values on form submission and validation also works with Yup
Here is a codesandbox demo for the same - https://codesandbox.io/s/wild-violet-fr9re
https://codesandbox.io/embed/wild-violet-fr9re?fontsize=14
import React, { Component } from "react";
import { Formik, Form, ErrorMessage } from "formik";
import * as Yup from "yup";
import Select from "react-select";
const debug = true;
class SelectForm extends Component {
constructor(props) {
super(props);
this.state = {
stateList: [],
stateCity: "",
selectedState: "",
citiesToLoad: []
};
}
handleState(opt) {
console.log(opt.value);
let citiesList = [];
Object.keys(this.state.stateCity).forEach(key => {
if (key === opt.value) {
this.state.stateCity[key].map((cityName, j) => {
citiesList.push(cityName);
});
}
});
this.setState({
selectedState: opt.value,
citiesToLoad: citiesList
});
}
handleMyCity(opt) {
console.log(opt.value);
}
componentDidMount() {
let stateLi = [];
fetch(`stateCity.json`)
.then(response => {
console.log(response);
return response.json();
})
.then(data => {
console.log(data);
for (let key in data) {
if (data.hasOwnProperty(key)) {
stateLi.push(key);
}
}
this.setState({ stateCity: data, stateList: stateLi });
})
.catch(err => {
console.log("Error Reading data " + err); // Do something for error here
});
}
render() {
const { selectedState, stateList, citiesToLoad } = this.state;
const newStateList = stateList.map(item => ({ label: item, value: item }));
const newCitiesToLoad = citiesToLoad.map(item => ({
label: item,
value: item
}));
return (
<div id="signupContainer" className="signinup-container">
<h3 className="mb-4"> Sign Up </h3>
<Formik
initialValues={{
state: selectedState,
city: ""
}}
validationSchema={Yup.object().shape({
state: Yup.string().required("Please select state."),
city: Yup.string().required("Please select city.")
})}
onSubmit={(values, { resetForm, setErrors, setSubmitting }) => {
setTimeout(() => {
console.log("Getting form values - ", values);
setSubmitting(false);
}, 500);
}}
enableReinitialize={true}
>
{props => {
const {
values,
touched,
dirty,
errors,
isSubmitting,
handleChange,
setFieldValue,
setFieldTouched
} = props;
return (
<Form id="signUpForm" className="signinupForm" noValidate>
<div className="form-group">
<label htmlFor="state" className="form-label">
State
</label>
<Select
name="state"
id="state"
onBlur={() => setFieldTouched("state", true)}
value={values.state}
onChange={(opt, e) => {
this.handleState(opt);
handleChange(e);
setFieldValue("state", opt.value);
}}
options={newStateList}
error={errors.state}
touched={touched.state}
/>
</div>
<div className="form-group">
<label htmlFor="city" className="form-label">
City
</label>
<Select
name="city"
id="city"
onBlur={() => setFieldTouched("city", true)}
value={values.city}
onChange={(opt, e) => {
this.handleMyCity(opt);
setFieldValue("city", opt.value);
}}
options={newCitiesToLoad}
/>
</div>
{isSubmitting ? (
<span className="loader-gif">
<img src={loading} alt="Loading..." />
</span>
) : null}
<button
type="submit"
className="btn btn-filled"
disabled={!dirty || isSubmitting}
>
Submit
</button>
{/*Submit */}
</Form>
);
}}
</Formik>
</div>
);
}
}
export default SelectForm;
Upon selecting any value from the selecet dropdown, my selected value should appear in select box
回答1:
You are setting the field value on onchange of select setFieldValue("state", opt.value);
so you don't need to set value for the <Select>
:
<Select
name="state"
id="state"
onBlur={() => setFieldTouched("state", true)}
onChange={(opt, e) => {
this.handleState(opt);
handleChange(e);
setFieldValue("state", opt.value);
}}
options={newStateList}
error={errors.state}
touched={touched.state}
/>
change for the both <Select>
回答2:
react-select accepts an object as a value so you need to pass an object of
let object = {
"label": "Andhra Pradesh",
"value": "Andhra Pradesh"
}
bypassing an object in value the selected value appears in the select box
Here is a codesandbox demo https://codesandbox.io/s/floral-fire-8txrt
so updated code is
import React, { Component } from "react";
import { Formik, Form, ErrorMessage } from "formik";
import * as Yup from "yup";
import Select from "react-select";
const debug = true;
class SelectForm extends Component {
constructor(props) {
super(props);
this.state = {
stateList: [],
stateCity: "",
selectedState: "",
citiesToLoad: []
};
}
handleState(opt) {
console.log(opt.value);
let citiesList = [];
Object.keys(this.state.stateCity).forEach(key => {
if (key === opt.value) {
this.state.stateCity[key].map((cityName, j) => {
citiesList.push(cityName);
});
}
});
this.setState({
selectedState: opt,
citiesToLoad: citiesList
});
}
handleMyCity(opt) {
console.log(opt.value);
}
componentDidMount() {
let stateLi = [];
fetch(`stateCity.json`)
.then(response => {
console.log(response);
return response.json();
})
.then(data => {
console.log(data);
for (let key in data) {
if (data.hasOwnProperty(key)) {
stateLi.push(key);
}
}
this.setState({ stateCity: data, stateList: stateLi });
})
.catch(err => {
console.log("Error Reading data " + err); // Do something for error here
});
}
render() {
const { selectedState, stateList, citiesToLoad } = this.state;
const newStateList = stateList.map(item => ({ label: item, value: item }));
const newCitiesToLoad = citiesToLoad.map(item => ({
label: item,
value: item
}));
return (
<div id="signupContainer" className="signinup-container">
<h3 className="mb-4"> Sign Up </h3>
<Formik
initialValues={{
state: selectedState,
city: ""
}}
validationSchema={Yup.object().shape({
state: Yup.string().required("Please select state."),
city: Yup.string().required("Please select city.")
})}
onSubmit={(values, { resetForm, setErrors, setSubmitting }) => {
setTimeout(() => {
console.log("Getting form values - ", values);
setSubmitting(false);
}, 500);
}}
enableReinitialize={true}
>
{props => {
const {
values,
touched,
dirty,
errors,
isSubmitting,
handleChange,
setFieldValue,
setFieldTouched
} = props;
return (
<Form id="signUpForm" className="signinupForm" noValidate>
<div className="form-group">
<label htmlFor="state" className="form-label">
State
</label>
<Select
name="state"
id="state"
onBlur={() => setFieldTouched("state", true)}
value={values.state}
onChange={(opt, e) => {
this.handleState(opt);
handleChange(e);
setFieldValue("state", opt);
}}
options={newStateList}
error={errors.state}
touched={touched.state}
/>
</div>
<div className="form-group">
<label htmlFor="city" className="form-label">
City
</label>
<Select
name="city"
id="city"
onBlur={() => setFieldTouched("city", true)}
value={values.city}
onChange={(opt, e) => {
this.handleMyCity(opt);
setFieldValue("city", opt);
}}
options={newCitiesToLoad}
/>
</div>
{isSubmitting ? (
<span className="loader-gif">
<img src={loading} alt="Loading..." />
</span>
) : null}
<button
type="submit"
className="btn btn-filled"
disabled={!dirty || isSubmitting}
>
Submit
</button>
{/*Submit */}
</Form>
);
}}
</Formik>
</div>
);
}
}
export default SelectForm;
来源:https://stackoverflow.com/questions/58502707/react-select-with-formik-not-updating-select-field-but-does-everything-else