Ad

Joining Firebase Tables In React

- 1 answer

I am hoping to display a list of user's notes from a Firebase DB inside of a React app.

After reading through the Firebase recommended approach on structuring data, I've created my database in the flattened format they recommend. The data structure looks something like this:

    notes
    - [noteKey]
      - note: [noteData]
      - created_at: [date]
      - updated_at: [date]
    ...
    users
      - [userKey]
         - name: [userName]
         - notes
           - [noteKey]: true
           ... 
    ...

Each user has an array called notes, which lists the noteKeys of the notes that they own.

So far I've been able to get the full list of notes (from all users, not what I want), and the user's list of noteKeys. The issue that I'm having is combining those two. I have seen the question about joining tables, but I have more of a React focused question:

In which React function does the join happen?

Right now my code looks like this:

    getInitialState: function(){
      return {
        notesList: []
      };
    },
    componentWillMount: function() {

      base = Rebase.createClass('https://appName.firebaseio.com');
      base.syncState('notes', {
        context: this,
        state: 'notesList',
        asArray: true,
        queries: {
          limitToLast: 20
        }
      });

      this.state.notesList.map(function(item, i) {         
        base.child("notes/" + item['.key'] + "/note").on('child_added', function(snapshot) {
          console.log(item['.key'])
        }); 
      });
    },

I see two issues with this.

  1. When the this.state.notesList.map function is called in componentWillMount, the array hasn't been populated with the Firebase data yet, so it looks like an empty array and returns an error.
  2. Once I solve #1, I'm not sure how to get the user specific notes into it's own array that's accessible by the rest of the component.

--

  • In which React timeline function should the join be happening?
  • How do the second table items (the user's notes) get added to an array that is accessible by the rest of the component?
Ad

Answer

You're working with an async library (re-base) here but you've written synchronous code.

What this means is base.syncState is going to fire off a request to your Firebase instance and in the meantime, your JavaScript is going to just keep happily executing down the line with or without results. It follows that this.state.notesList.map is going to map over an empty array since JS is going to execute faster than a round trip to the server.

Looking at the options available for the syncState method, there's one called then that executes a callback.

then: (function - optional) The callback function that will be invoked when the initial listener is established with Firbase. Typically used (with syncState) to change this.state.loading to false.

This makes me think that it fires after you get your data from Firebase.

Try running your .map in there since you'll actually have the data you want.

componentWillMount: function() {

  base = Rebase.createClass('https://appName.firebaseio.com');
  base.syncState('notes', {
    context: this,
    state: 'notesList',
    asArray: true,
    queries: {
      limitToLast: 20
    },
    then: function() {
      this.state.notesList.map(function(item, i) {         
        base.child("notes/" + item['.key'] + "/note").on('child_added', function(snapshot) {
          console.log(item['.key'])
        }); 
      });
    }
  });
}
Ad
source: stackoverflow.com
Ad