1

I used the same function I got on a react native in a react app and it didn't work, looks like I couldn't access the sate although I defined it in the constructor, the goal is to push data to firebase, I tried with random strings and it definitely works, it's just when using the form that it crashes.

As you can see I'm using text components to take a look a the state on the HTML page :

import React, { Component } from 'react';
import fire from './config/Fire';

class Home extends Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.state = {
      isOpen: false,
      title: '',
      description: '',
      loading: true
    };
  }

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

  saveData(e) {
    e.preventDefault();
    let title = this.state.title;
    let description = this.state.description;
    const { currentUser } = fire.auth();
    fire
      .database()
      .ref(`/master/setup/`)
      .push({ title, description })
      .then(() => {
        this.setState({ loading: false }).catch(error => {
          console.log(error);
        });
      });
  }

  render() {
    return (
      <div>
        <Container>
          <Row>
            <Col sm="2" lg="3" />
            <Col sm="8" lg="6">
              <h1>General Setup</h1>

              <form>
                <div class="form-group">
                  <label for="exampleInputEmail1">Title</label>
                  <input
                    value={this.state.title}
                    onChange={this.handleChange}
                    name="title"
                    class="form-control"
                    id="title"
                    placeholder="Enter event title"
                  />
                </div>
                <div class="form-group">
                  <label for="exampleInputEmail1">Description</label>
                  <input
                    value={this.state.description}
                    onChange={this.handleChange}
                    name="description"
                    class="form-control"
                    id="description"
                    placeholder="Enter event description"
                  />
                </div>
                <button onClick onClick={this.saveData} class="btn btn-primary">
                  Submit
                </button>
              </form>

              <p>{this.state.title}</p>
              <p>{this.state.description}</p>
              <p>{this.state.loading.toString()}</p>
            </Col>
            <Col sm="2" lg="3" />
          </Row>
        </Container>
      </div>
    );
  }
}

export default Home;

TypeError: Cannot read property 'state' of undefined

Please, someone, let me know what's going on with this code?

You Nguyen
  • 9,961
  • 4
  • 26
  • 52

3 Answers3

0

You forgot to bind scope to saveData method. Do it in constructor same as you bind it to handleChange method.

constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.saveData = this.saveData.bind(this);
    this.state = {
      isOpen: false,
      title: '',
      description: '',
      loading: true,
  };

or

change saveData definition to one that uses arrow function syntax from ES6

saveData = (e) => {...function body as you already have it}

and parent scope will be bind for you by default

azrahel
  • 1,143
  • 2
  • 13
  • 31
  • I would just like to point that my answer was posted 7 seconds before @imjared answer :D I have not copied it – azrahel Sep 28 '18 at 15:17
0

You need to bind saveData in constructor.

this.saveData = this.saveData.bind(this);

imjared
  • 19,492
  • 4
  • 49
  • 72
0

You can change saveData to an arrow function hence binding isn't required. This is an ES6 version, do something like below

saveData = e => {
  e.preventDefault();
  let title = this.state.title;
  let description = this.state.description;
  const { currentUser } = fire.auth();
  fire.database().ref(`/master/setup/`)
      .push({ title, description })
      .then(() => {
      this.setState({ loading: false})
      .catch((error) => {
          console.log(error);
      })
  });
}
Hemadri Dasari
  • 32,666
  • 37
  • 119
  • 162
  • Damn, you beat me to it! – Shivam Gupta Sep 28 '18 at 15:21
  • That's what I got in the very beginning, not sure why I ditched the arrow function. Thanks –  Sep 28 '18 at 15:25
  • important to understand that using arrow function is just another aproach to binding, as it is not required in its case ***because*** binding parent scope is done for you by default – azrahel Sep 28 '18 at 15:27
  • @blvckasvp if you want to understand more about which is preferred arrow function or regular function with manual binding check here https://stackoverflow.com/questions/52031147/react-which-is-recommended-arrow-or-normal-function. It has detailed explanation when to use what – Hemadri Dasari Sep 28 '18 at 15:30