Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Formik values not updating with state

Tags:

Here's the template for a form I'm writing with Formik and react-bootstrap. I'm finding a very strange error: if I initialise my state with dummy data in the constructor, it works fine; but if I call setState with the exact same data in componentDidMount to simulate an API call, it breaks horribly.

Specifically, I find that the state variable alertVehicles array can have non-zero length, but the corresponding Formik values.alertVehicles variable can be empty. Right now, the form as written renders no checkboxes. If I use alertVehicles instead of values.alertVehicles in my guard clause, then it blows up with an error Cannot read property 'selected' of undefined.

import React, {Component} from 'react';
import Form from 'react-bootstrap/Form';
import { Formik } from 'formik';
import Button from 'react-bootstrap/Button';


class Alerts extends Component {
    constructor(props) {
        super(props);
        this.loadAlertData = this.loadAlertData.bind(this);
        this.state = {
            alertRecipient: {},
            alertId: '',
            alertVehicles: []
        }
    }

    componentDidMount(){
        this.loadAlertData();
    }

    loadAlertData(){
        // this will be an API call eventually, obviously.
        // if this is initialised in the constructor then everything works!
        this.setState( {
            alertRecipient: {
                name: 'Rob',
                simNumber: '0123456789',
            },
            alertId: 1,
            alertVehicles: [
                {id: 1, vrn: 'vehicle A', selected: true },
                {id: 2, vrn: 'vehicle B', selected: false },
                {id: 3, vrn: 'vehicle C', selected: true }
            ]
        })
    }

    render() {
        const { alertRecipient, alertId, alertVehicles } = this.state;
        return (
            <>
                <Formik
                    initialValues={{ alertRecipient, alertId, alertVehicles }}
                    onSubmit={ values => {
                            window.alert(JSON.stringify(values))
                        }
                    }
                    render={({values, handleChange, handleSubmit}) => (
                        <Form onSubmit={handleSubmit}>
                            <Form.Label>Name</Form.Label>
                            <Form.Control
                                type="text"
                                name="alertRecipient.name"
                                value={values.alertRecipient.name}
                                onChange={handleChange}
                            />
                            <Form.Label>Phone number</Form.Label>
                            <Form.Control
                                type="text"
                                name="alertRecipient.simNumber"
                                value={values.alertRecipient.simNumber}
                                onChange={handleChange}
                            >
                            </Form.Control>
                            <Form.Label>Vehicles</Form.Label>
                            {
                                //get an error if we just use alertVehicles.length here??
                                values.alertVehicles.length === 0 ? null : alertVehicles.map((veh, index) => (

                                    <Form.Check type="checkbox"
                                                key={veh.id}
                                                label={veh.vrn}
                                                name={`alertVehicles[${index}].selected`}
                                                checked={values.alertVehicles[index].selected}
                                                onChange={ handleChange }
                                    />
                                ))
                            }
                            <Button type="submit">Save</Button>
                        </Form>
                    )
                    }
                />
            </>
        )
    }

}

export default Alerts;

I don't understand

  1. Why the code works when I set my dummy data in the constructor but not in componentDidMount
  2. Why values.alertVehicles doesn't appear to be in sync with alertVehicles.

Thanks in advance for any help.

like image 322
rwold Avatar asked May 21 '19 21:05

rwold


People also ask

How do you reinitialize Formik values?

We can reset the form by using the resetForm() method of formik. We can register it on the onClick event of the reset button.

What is dirty Formik?

Returns true if values are not deeply equal from initial values, false otherwise. dirty is a readonly computed property and should not be mutated directly.

How do I get Formik values before submitting?

it is very simple just do console. log(formik. values) and you will get all the values without submitting it.


1 Answers

For some reason this is Formik's default behaviour, and you need to supply the enableReinitialize prop to override it: https://github.com/jaredpalmer/formik/issues/811

like image 89
rwold Avatar answered Sep 24 '22 14:09

rwold