Search code examples
reactjssetstate

React setState not setting state of input field


I am using Gatsby. This is my code:

import React from "react"

class ContactCard extends React.Component {
    constructor(props) {
        super(props);
        this.state = { form: { name: "test" }, message: ""};
        this.handleChange = this.handleChange.bind(this);
    }
    handleSubmit = e => {
        e.preventDefault();
    };

    handleChange = e => {
        console.log("handleChange: " + e.target.name + " = " + e.target.value);
        this.setState({ [e.target.name]: e.target.value, message: "event value: " + e.target.value });
        /*
        I also tried the following:
        this.setState({ name: e.target.value, message: "event value: " + e.target.value });
        */
    }

    render() {
        const { form: { name }, message } = this.state;
        return (
            <>
                <p>{message} name: {name} </p>
                <form onSubmit={this.handleSubmit}>
                    <input
                        type="text"
                        value={name}
                        name="name"
                        onChange={this.handleChange}
                    />
                </form>
            </>
        );
    }
}
export default ContactCard

When I type in the input box I see the following in the console log:

handleChange: name = testg

And the P tag changes to have the following text:

event value: testg name: test

The input box's value does not change it remains the same no matter what I do. As commented in my code, I also tried to setState on name directly instead of using the event name, that did not work. I also tried the following:

handleChange = e => {
    console.log("handleChange: " + e.target.name + " = " + e.target.value);
    var newState = { [e.target.name]: e.target.value, message: "event value: " + e.target.value };
    this.setState(newState);
}

This results in the same behavior. What am I missing?


Solution

  • Issue

    You are incorrectly setting state. Your state shape has name as a property of state.form, so the setState needs to match this shape.

    Solution

    Nest [e.target.name]: e.target.value in the form object. Ensure you shallow copy any existing form state as well. The React setState will shallow merge the root object, but it won't do a deep merge of nested state updates.

    Since react state updates are asynchronous and (currently in react 16.x) react synthetic events are typically quickly nullified and returned to the event pool, you may also want to save the event name and value properties before enqueueing the state update.

    handleChange = (e) => {
      const { name, value } = e.target;
      this.setState((prevState) => ({
        form: {
          ...prevState.form,
          [name]: value
        },
        message: "event value: " + value
      }));
    };
    

    Edit react-setstate-not-setting-state-of-input-field