1

I'm in the process of learning React. I was doing one of the refractor exercises as below:

    import React, { Component } from "react";

    import "./App.css";

    class App extends Component {
      state = {
        form: {
          firstName: "",
          lastName: "",
          email: "",
          password: ""
        }
      };

      handleFirstNameChange = e => {
        this.setState({
          form: {
            firstName: e.target.value
          }
        });
      };

      handleLastNameChange = e => {
        this.setState({
          form: {
            lastName: e.target.value
          }
        });
      };

      handleEmailChange = e => {
        this.setState({
          form: {
            email: e.target.value
          }
        });
      };

      handlePasswordChange = e => {
        this.setState({
          form: {
            password: e.target.value
          }
        });
      };

      validateForm = () => {
        const formInputs = ["firstName", "lastName", "email", "password"];

        for (let i = 0; i < formInputs.length; i++) {
          const inputName = formInputs[i];

          if (!this.state.form[inputName].length) {
            return false;
          }
        }

        return true;
      };

      handleSubmit = () => {
        if (this.validateForm()) {
          console.log("Success!");
        } else {
          console.log("Failure!");
        }
      };

      render() {
        return (
          <div
            style={{
              display: "flex",
              justifyContent: "center",
              alignItems: "center"
            }}
          >
            <form
              className="Form"
              onSubmit={e => {
                e.preventDefault();
                this.handleSubmit();
              }}
            >
              <input name="firstName" onChange={this.handleFirstNameChange} />
              <input name="lastName" onChange={this.handleLastNameChange} />
              <input name="email" onChange={this.handleEmailChange} />
              <input name="password" onChange={this.handlePasswordChange} />
              <button className="no-padding">Submit</button>
            </form>
          </div>
        );
      }
    }

    export default App;

and I refactored it to :

  import React, { Component } from "react";

  import "./App.css";

  class App extends Component {
    state = {
      form: {
        firstName: "",
        lastName: "",
        email: "",
        password: ""
      }
    };

    handleChange = e => {
      this.setState({
        form: {
          [e.target.name]: e.target.value
        }
      });
    };

    validateForm = () => {
      const formInputs = ["firstName", "lastName", "email", "password"];

      for (let i = 0; i < formInputs.length; i++) {
        const inputName = formInputs[i];

        if (!this.state.form[inputName].length) {
          return false;
        }
      }

      return true;
    };

    handleSubmit = () => {
      if (this.validateForm()) {
        console.log("Success!");
      } else {
        console.log("Failure!");
      }
    };

    render() {
      return (
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            alignItems: "center"
          }}
        >
          <form
            className="Form"
            onSubmit={e => {
              e.preventDefault();
              this.handleSubmit();
            }}
          >
            <input name="firstName" onChange={this.handleChange} />
            <input name="lastName" onChange={this.handleChange} />
            <input name="email" onChange={this.handleChange} />
            <input name="password" onChange={this.handleChange} />
            <button className="no-padding">Submit</button>
          </form>
        </div>
      );
    }
  }

  export default App;

For some reason, I got an error when I submit my form -

TypeError: Cannot read property 'length' of undefined

I was wondering what did I do wrong in my code?

Also is there a better way to refactor the code even more?

2
  • 1
    its because state variable name is email and in array you have defined: emailAddress. Error is because this.state.form.emailAddress will be undefined, and that why Cannot read property 'length' of undefined. Commented Nov 26, 2018 at 18:14
  • @MayankShukla I changed 'emailAddress' to 'email' in my array and still getting the same error Commented Nov 26, 2018 at 18:19

2 Answers 2

4

Its because you are updating the state in wrong way, during update each time you are deleting all other key value pairs from the form array, instead of just updating any one key value.

Update it like this:

handleChange = e => {
  const { name, value } = e.target;
  this.setState(prevState => ({
    form: {

      // all other key value pairs of form object
      ...prevState.form,

      // update this one specifically
      [name]: value
    }
  }));
};

Check this snippet to get the better idea:

let obj1 = { a:1, b:2 };
let obj2 = { a:1, b:2 };

let temp = 'a';

obj1 = { [temp]: 10 };

obj2 = { ...obj2, [temp]: 10 };

console.log('obj1', obj1);
console.log('obj2', obj2);

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for explaining!
1

Here is the working code snippet. There was two mistakes one is in the handleChange event setting the right values in the state. Email address state property name being different at two places

https://codesandbox.io/s/5kz5wko31k

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.