Working with database Snapshot
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