React-select with Formik not updating select field but does everything else

Gaurav picture Gaurav · Oct 22, 2019 · Viewed 7k times · Source

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

Answer

Kiran LM picture Kiran LM · Oct 23, 2019

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>