douglasrcjames
douglasrcjames

Reputation: 1645

React/Firebase error: Cannot read property 'database' of undefined

To preface, I am just beginning to dive into React.js, so solution might be simple.

I am using React.js with firebase and react-router for a basic multipage site with a form that posts text. On the TicketList page, I am attempting to do a data post to Firebase, which works, but when I go to another page and come back to the TicketList page, I get the error: TypeError: Cannot read property 'database' of undefined.

From the tutorial I am following, the code is the same, except all my TicketList code is on the App.js, since the tutorial didn't have react-router. Not sure if this structure has to do with this issue. The tutorial also doesn't have the this.app = firebase.initializeApp(DB_CONFIG); inside if (!firebase.apps.length), but without that bit I get the error: Firebase App named '[DEFAULT]' already exists.

If I put this.database = this.app.database().ref().child('tickets'); inside the if (!firebase.apps.length) I get the error: TypeError: Cannot read property 'on' of undefined, but now I think I am straying too far from the original problem, and I think my understanding is off. Anyone have some direction for me? Thanks!

Structure:

src 
    > components 
    > config
      > config.js
    > routes
      > About.js
      > TicketList.js
      > index.js
    > App.js

TicketList.js :

import React, { Component } from 'react';
import Ticket from '../components/Ticket.js'
import TicketForm from '../components/TicketForm.js'
import { DB_CONFIG } from '../config/config.js';
import firebase from 'firebase/app';
import 'firebase/database';

// CSS
import '../assets/css/TicketList.css';
import '../assets/css/App.css';

class TicketList extends Component {
  constructor(props){
    super(props);
    this.addTicket = this.addTicket.bind(this);
    this.removeTicket = this.removeTicket.bind(this);
    if (!firebase.apps.length) {
      this.app = firebase.initializeApp(DB_CONFIG);
      this.database = this.app.database().ref().child('tickets');
    }

    // We're going to setup the React state of our component
    this.state = {
      tickets: [],
    }
  }

  componentWillMount(){
    const previousTickets = this.state.tickets;

    // DataSnapshot
    this.database.on('child_added', snap => {
      previousTickets.push({
        id: snap.key,
        ticketContent: snap.val().ticketContent,
      })

      this.setState({
        tickets: previousTickets
      })
    })

    this.database.on('child_removed', snap => {
      for(var i=0; i<previousTickets.length; i++){
        if(previousTickets[i].id === snap.key){
          previousTickets.splice(i, 1);
        }
      }

      this.setState({
        tickets: previousTickets
      })
    })
  }

  addTicket(ticket){
    this.database.push().set({ ticketContent: ticket });
  }

  removeTicket(ticketId){
    this.database.child(ticketId).remove();
  }

  render() {
    return (
      <div>
        <div className="m-container">
          <h1>Open Questions</h1>
          <hr/>
        </div>
        <div>
        {
          this.state.tickets.map((ticket) => {
              return (
                <Ticket 
                ticketContent={ticket.ticketContent} 
                ticketId={ticket.id} 
                key={ticket.id} 
                removeTicket={this.removeTicket} />
              )
          })
        }

        </div>
        <div>
          <TicketForm addTicket={this.addTicket} />
        </div>
      </div>
    );
  }
}

export default TicketList;

Upvotes: 0

Views: 5764

Answers (1)

jshawl
jshawl

Reputation: 3483

The problem is here:

this.app = firebase.initializeApp(DB_CONFIG);
this.database = this.app.database().ref().child('tickets');

firebase.initialize is asynchronous, which is why this.app is undefined by the time you reference it.

instead, try:

firebase.initializeApp(DB_CONFIG);
this.database = firebase.database().ref().child('tickets');

Upvotes: 1

Related Questions