6
votes

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

2

2 Answers

5
votes

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>

1
votes

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;