'How to update specific form field in formik when value changes in redux store?

I am using formik in my react application. I have initialized all the form values from a state. But I wanted to update a specific form field if props in the redux store change. Below is my formik form:

<Formik
initialValues={this.state.branchData}
enableReinitialize={true}
onSubmit={this.formSubmit} >
{({ values, setFieldValue }) => (
    <Form >
        <Row>
            <Col lg="12">

                <FormGroup className="col-6">
                    <Input type="select" value={values.StateId} name="StateId" onChange={this.handleChange(setFieldValue)}>
                        <option value='' >Select State</option>
                        {this.props.stateList && this.props.stateList.map((item, i) => (
                            <option key={i} value={item.StateId}>
                                {item.StateName}
                            </option>
                        ))}
                    </Input>
                    {this.validator.message('state', values.StateId, 'required')}
                    <Label className="impo_label">Select State</Label>
                </FormGroup>

                <FormGroup className="col-6">
                    <Field className="form-control" name="GstNo" type="text" maxLength="15" />
                    <Label className="impo_label">GST No</Label>
                    {this.validator.message('gst no', values.GstNo, 'required|min:15|max:15')}
                </FormGroup>


            </Col>
        </Row>
    </Form>
)}

Now, When I change state from the dropdown, an api will get invoke which will return gst no by state id. I want to update the gst no field with the value recieved from the api in the props. If the gst no received is null then I want user to input the gst no, but if gst no is recieved from the api, I want to update the gst no field in form with the value received in props and disable the form input. I cannot update the gstno in this.state.branchData as this will reset the form values with values in this.state.branchData.

Does anyone have any idea about how to achieve this in formik?



Solution 1:[1]

You can enable enableReinitialize property of Formik to update the field.

<Formik
   enableReinitialize={true}
   initialValues={...}
>
....

Solution 2:[2]

When data comes from api. You can just easy change value of field like this:

setFieldValue('GstNo', valueFromApi)

Solution 3:[3]

It's better to use setFieldValue, When the API gets some value or any props/dependency value changes, you can use useEffect to handle it, For Example: I'm getting setFieldValue function as a prop from parent component.

useEffect(() => {
    if (
        values.parentCategoryId &&
        !categories?.data?.find(category => category.id === values.categoryId)
            ?.hasFurnishingStatus
    ) {
        setFieldValue('furnishingStatus', '');
    }
}, [values?.categoryId]);

Here the furnishingStatus is the name of the field for which I'm setting the value.

<Field name="furnishingStatus" component={RadioGroup} row>{...}</Field>

Solution 4:[4]

you can use this method

     useEffect(() => {
        // get user and set form fields
        userService.getById(id).then(user => {
        const fields = ['title', 'firstName', 'lastName', 'email', 'role'];
        fields.forEach(field => setFieldValue(field, user[field], false));
        setUser(user);
        });
    }, []);

Solution 5:[5]

I defined a state variable for maintaining the gstNo that will be fetched from the API based on the state id selected from the drop-down. Like this:

 this.state = {
   gstNo: null,
 };

So, when the API will get invoked and the response is received, gstNo props will be updated in the redux store.

this.state.gstNo will be updated inside the UNSAFE_componentWillReceiveProps(), when this.props.gstNo changes. Like Below:

if (this.props.gstNo !== nextprops.gstNo) {
  let gstNo;
  if (nextprops.gstNo) {
      gstNo = nextprops.gstNo;
  } 
  else {
      gstNo = null;
  }

 this.setState({
   gstNo: gstNo,
  });

And to assign this.state.gstNo value to formik, I simply wrote this:

<FormGroup className="col-6">
    <Field
        className="form-control"
        name="GstNo"
        disabled={this.state.gstNo}
        type="text"
        maxLength="15"
        value={
            (values.GstNo = this
                .state.gstNo
                ? this.state.gstNo
                : values.GstNo)
        }
    />
    <Label className="impo_label">
        GST No
    </Label>
</FormGroup>

So as soon as this.state.gstNo would be having some value, it would be reflected in formik form's text field and the textbox will be disabled.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MsiLucifer
Solution 2
Solution 3 Awais Mughal
Solution 4 Saif Ullah
Solution 5 Sunny