Triyugi Narayan Mani
Triyugi Narayan Mani

Reputation: 3109

Uncaught TypeError: Cannot read property 'value' of undefined in REACT JS

I am creating a login form using REACT JS as front-end and PHP as back-end. I am trying to get input values. Code is as below:

import React, { Component} from 'react';
import ReactDOM from 'react-dom';
import {Button, IconButton} from 'react-toolbox/lib/button';
import Input from 'react-toolbox/lib/input';

export default class Login extends React.Component {

constructor() {
    super();
    this.state = {email: ''};
    this.state = {password: ''};
    this.onSubmit = this.onSubmit.bind(this);
    this.handleEmailChange = this.handleEmailChange.bind(this);
    this.handlePasswordChange = this.handlePasswordChange.bind(this);
}
handleEmailChange(e) {
    this.setState({email: e.target.value});
}
handlePasswordChange(e) {
    this.setState({password: e.target.value});
}
onSubmit() {
    fetch('http://xyz/check-login', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email: this.state.email,
        password: this.state.password,
      })
    })
}

And form is as below:

<form name="Login">
<Input type="text" name="email" value={this.state.email} placeholder="Email Id" className="form-control" onChange={this.handleEmailChange} />
<Input name="password" value={this.state.password} placeholder="Password" type="password" className="form-control m-b-10" onChange={this.handlePasswordChange} />   
<Button type="button" className="m-t-20 orange" label="Sign in " onClick={this.onSubmit} /> 
</form>

But getting the following error:

Uncaught TypeError: Cannot read property 'value' of undefined

I am using react-toolbox. So, I am using component from https://github.com/react-toolbox/react-toolbox/blob/dev/components/input/Input.js and component from https://github.com/react-toolbox/react-toolbox/blob/dev/components/button/Button.js.

Upvotes: 6

Views: 41721

Answers (5)

ParisaN
ParisaN

Reputation: 2092

If you use Formik, You should set initialValues for it.

<Formik
  initialValues={{
    email: '',
    password: '',
  }}
  onSubmit={(values) => {
    console.log("formik", values)
  }}
>
         

Upvotes: 0

Luk&#225;š Unzeitig
Luk&#225;š Unzeitig

Reputation: 439

First change your this.state in constructor to single - this.state = {emai:'',password:''}, then try to bind handleEmailChange and handlePasswordChange inside of input instead in constructor, u need to set this direct to input,

UPDATE

or if Input and Button are components, u need implement changeMethod and onChange event in them, and send value back to component Login via callback

HOW IT WORKS -

 class Input extends React.Component{
            constructor(props){
                super(props);
                this.state= {
                    value : this.props.value
                }
            }
            componentWillReceiveProps(nextProps){
                 this.setState({
                      value: nextProps.value,
                  })
            }

            render(){
                return(
                    <input onChange={this.handleChangeValue.bind(this)} type="text" name={this.props.name} value={this.state.value} placeholder={this.props.placeholder} className={**just class name or send via props too**}  />
                )
            }
            handleChangeValue(e){
                this.setState({value:e.target.value});
                this.props.changeValue(e.target.value); 
            }
  }
        
        class Login extends React.Component{
            constructor(props){
                super(props);
                this.state= {
                    emailValue : '',
                    passwordValue: '',
                    ...
                }
            }
            render(){
                return(
                      <div>
                        <Input type="text" name='email' value={this.state.emailValue} placeholder={'Write email'} className='someName' changeValue={this.changeEmailValue.bind(this)} />
                        <Input type="text" name='password' value={this.state.passwordValue} placeholder={'Write password'} className='someName' changeValue={this.changePasswordValue.bind(this)} /> 
                     
                      </div>

                    )
               }
            changeEmailValue(value){
                this.setState({emailValue:value});
            }
        
            changePasswordValue(value){
                this.setState({passwordValue:value});
            }
        }

Upvotes: 5

Boky
Boky

Reputation: 12064

First of all, what are <Input ..../> and <Button .../>? Are they your components or they are only form input fields?

I suppose that they are only form fields, thus they need to be in lower case <input ..../> , <button .../>.

Try to bind your functions inside render, like : this.functionName.bind(this).

This is a working code :

class Test extends React.Component {
    constructor(props){
        super(props);

      this.state = {
          email: '',
          password: '',
      };
    }

    handleEmailChange(e) {
        this.setState({email: e.target.value});
    }
    handlePasswordChange(e) {
        this.setState({password: e.target.value});
    }


    render(){
        return (
        <div>
            <form name="Login">
              <input type="text" name="email" value={this.state.email} placeholder="Email Id" className="form-control" onChange={this.handleEmailChange.bind(this)} />
              <input name="password" value={this.state.password} placeholder="Password" type="password" className="form-control m-b-10" onChange={this.handlePasswordChange.bind(this)} />   
              <button type="button" className="m-t-20 orange" label="Sign in " onClick={this.onSubmit}>Sign in</button> 
          </form>
        </div>
      )
    }
}

React.render(<Test />, document.getElementById('container'));

Here is the fiddle.

UPDATE

I tested it here :

 constructor(props){
    super(props);

    this.state = {
            name: '',
        email: ''
    }
  }

  handleChange(name, value){
    let state = this.state;
    state[name] = value;
    this.setState({state});

  }

  render () {
    return (
      <section>
        <Input type='text' label='Name' name='name' value={this.state.name} onChange={this.handleChange.bind(this, 'name')} maxLength={16} />
        <Input type='email' label='Email address' icon='email' value={this.state.email} onChange={this.handleChange.bind(this, 'email')} />
      </section>
    );
  }

I'm not sure how it works, but it pass name and value as params to the handleChange function, thus, you can get value as a second param. You don't need event.

Upvotes: 6

Rob Lynch
Rob Lynch

Reputation: 611

Since you are using a custom component <Input/>, it is likely whatever special code that component has is abstracting away the default event passed from the built-in component <input/>. (note the lower case "i") So maybe you need it to read:

handleEmailChange(value) {
    this.setState({email: value});
}
handlePasswordChange(value) {
    this.setState({password: value});
}

Regardless the fix is likely that onChange is not returning an event, but some other value you were not expecting.

Upvotes: 2

Mayank Shukla
Mayank Shukla

Reputation: 104379

Instead on binding events in the constructor bind it with the input fields, it will solve your problem. one more suggestion: you are using two state object, Don't use two separate state variable initialisation, define it like this:

this.state = {
    email: '',
    password: '',
};

Upvotes: 1

Related Questions