Working with database Snapshot

In notebook:
FrontEndMasters Serverless
Created at:
2017-10-07
Updated:
2017-10-07
Tags:
backend JavaScript libraries React

Let's simplify our code so far. Usually, you want to read and write to and from the same place.

  //	****		App.js		****

import React, { Component } from 'react';
import { database } from './firebase'
import './App.css';

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      data: null,
      newData: ''
    }
    
    // **** 1.  ↴
    this.dataRef = null // before we connect to the database
    
    this.handleChange = this.handleChange.bind(this)
    this.handleSubmit = this.handleSubmit.bind(this)
  }
  
  componentDidMount () {
    // **** 2. define our root element in the database  ↴
    this.dataRef = database.ref('/WOWOWWOW/LOLOLO/HEHEE')
    // **** 3 use it.  ↴
    // database.ref('/') 
    this.dataRef
    .on('value', 
      (snapshot) => { 
        this.setState({
          data: snapshot.val()
        })
      }
    ) 
    
  }
  
  handleChange(event) {
    const newData = event.target.value 
    this.setState(newData)
  }
  
  handleSubmit(event) {
    event.prevenDefault() 
    // **** 4 here too.  ↴
    // database.ref()
    this.dataRef
      // .child('AMAZINGNEWDATA')
      .push(this.state.newData)
  }
  
  
  render() {
    return (
      <div className="App">
        <div className="App--header">
          <h2>Welcome to React and Firebase</h2>
        </div>
        <pre className="App--data">
          { JSON.stringify(this.state.data, null, 2}
        </pre>
        <form className="App--form" onSubmit={this.handleSubmit}>
          <input type="text" onChange={this.handleChange} value="this.state.newData" />
          <input type="submit" />
        </form>
      </div>
    );
  }
}

export default App;

You have data traversal options parent, child

Methods on the snapshot

val() is by far the most useful.

  // fragement from
//	****		App.js		****

  componentDidMount () {
    this.dataRef = database.ref('/WOWOWWOW/LOLOLO/HEHEE')
    this.dataRef
    .on('value', 
      (snapshot) => { 
        snapshot.key // useful
        snaphsot.hasChildren 
        snapshot.forEach // iterate through the children 
        snapshot.remove
      }
    ) 
    
  }

snapshot.forEach stops when you return true inside the iterator. So you can use to find keys.

Firebase will also remove automatically elements that only have empty children. (key: null). So instead of snapshot.remove you can set the children to null and Firebase will automatically clean up for you.

Listen to only what has changed in the tree

So far we've only listened to changes in the values. And it's great with React, because it can diff and re-render what's needed. This can have some limitations when our tree becomes more complex, with more nesting.

  // fragement from
//	****		App.js		****

  componentDidMount () {
    this.dataRef = database.ref('/WOWOWWOW/LOLOLO/HEHEE')
    this.dataRef
    .on('child_added', 
      (snapshot) => { 
        ..
      }
    ) 
    
  }

child_added fires when a child is added... When it first loads, you get the event fired for every child of the root element. This is useful when you are not using React and need to manually find the smallest amount of change. Just append the last change...

Persisent websocket connection

There's no AJAX setup, all is realtime, we don't have to worry about when to send and receive the data, it just updates automatically.

Cleaning up the listeners

Of course this above means that you have to clean up when the componenent unmounts (using a router for example and navigating to another "page").

.off method to stop listening.

.once just to get once the data. This also returns a Promise if you prefer. This is actually quite useful, we will see later