|
1 | 1 |
|
| 2 | +# Realtime Database |
| 3 | + |
| 4 | +Firestack mimics the [Web Firebase SDK Realtime Database](https://firebase.google.com/docs/database/web/read-and-write), whilst |
| 5 | +providing support for devices in low/no data connection state. |
| 6 | + |
| 7 | +All Realtime Database operations are accessed via `database()`. |
| 8 | + |
| 9 | +Basic read example: |
| 10 | +```javascript |
| 11 | +firestack.database() |
| 12 | + .ref('posts') |
| 13 | + .on('value', (snapshot) => { |
| 14 | + const value = snapshot.val(); |
| 15 | + }); |
| 16 | +``` |
| 17 | + |
| 18 | +Basic write example: |
| 19 | +```javascript |
| 20 | +firestack.database() |
| 21 | + .ref('posts/1234') |
| 22 | + .set({ |
| 23 | + title: 'My awesome post', |
| 24 | + content: 'Some awesome content', |
| 25 | + }); |
| 26 | +``` |
| 27 | + |
| 28 | +## Unmounted components |
| 29 | + |
| 30 | +Listening to database updates on unmounted components will trigger a warning: |
| 31 | + |
| 32 | +> Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the undefined component. |
| 33 | +
|
| 34 | +It is important to always unsubscribe the reference from receiving new updates once the component is no longer in use. |
| 35 | +This can be achived easily using [Reacts Component Lifecycle](https://facebook.github.io/react/docs/react-component.html#the-component-lifecycle) events: |
| 36 | + |
| 37 | +Always ensure the handler function provided is of the same reference so Firestack can unsubscribe the ref listener. |
| 38 | + |
| 39 | +```javascript |
| 40 | +class MyComponent extends Component { |
| 41 | + constructor() { |
| 42 | + super(); |
| 43 | + this.ref = null; |
| 44 | + } |
| 45 | + |
| 46 | + // On mount, subscribe to ref updates |
| 47 | + componentDidMount() { |
| 48 | + this.ref = firestack.database().ref('posts/1234'); |
| 49 | + this.ref.on('value', this.handlePostUpdate); |
| 50 | + } |
| 51 | + |
| 52 | + // On unmount, ensure we no longer listen for updates |
| 53 | + componentWillUnmount() { |
| 54 | + if (this.ref) { |
| 55 | + this.ref.off('value', this.handlePostUpdate); |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + // Bind the method only once to keep the same reference |
| 60 | + handlePostUpdate = (snapshot) => { |
| 61 | + console.log('Post Content', snapshot.val()); |
| 62 | + } |
| 63 | + |
| 64 | + render() { |
| 65 | + return null; |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +``` |
| 70 | + |
| 71 | +## Usage in offline environments |
| 72 | + |
| 73 | +### Reading data |
| 74 | + |
| 75 | +Firstack allows the database instance to [persist on disk](https://firebase.google.com/docs/database/android/offline-capabilities) if enabled. |
| 76 | +To enable database persistence, call the following method before calls are made: |
| 77 | + |
| 78 | +```javascript |
| 79 | +firestack.database().setPersistence(true); |
| 80 | +``` |
| 81 | + |
| 82 | +Any subsequent calls to Firebase stores the data for the ref on disk. |
| 83 | + |
| 84 | +### Writing data |
| 85 | + |
| 86 | +Out of the box, Firebase has great support for writing operations in offline environments. Calling a write command whilst offline |
| 87 | +will always trigger any subscribed refs with new data. Once the device reconnects to Firebase, it will be synced with the server. |
| 88 | + |
| 89 | +The following todo code snippet will work in both online and offline environments: |
| 90 | + |
| 91 | +```javascript |
| 92 | +// Assume the todos are stored as an object value on Firebase as: |
| 93 | +// { name: string, complete: boolean } |
| 94 | + |
| 95 | +class ToDos extends Component { |
| 96 | + constructor() { |
| 97 | + super(); |
| 98 | + this.ref = null; |
| 99 | + this.listView = new ListView.DataSource({ |
| 100 | + rowHasChanged: (r1, r2) => r1 !== r2, |
| 101 | + }); |
| 102 | + |
| 103 | + this.state = { |
| 104 | + todos: this.listView.cloneWithRows({}), |
| 105 | + }; |
| 106 | + |
| 107 | + // Keep a local reference of the TODO items |
| 108 | + this.todos = {}; |
| 109 | + } |
| 110 | + |
| 111 | + // Load the Todos on mount |
| 112 | + componentDidMount() { |
| 113 | + this.ref = firestack.database().ref('users/1234/todos'); |
| 114 | + this.ref.on('value', this.handleToDoUpdate); |
| 115 | + } |
| 116 | + |
| 117 | + // Unsubscribe from the todos on unmount |
| 118 | + componentWillUnmount() { |
| 119 | + if (this.ref) { |
| 120 | + this.ref.off('value', this.handleToDoUpdate); |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + // Handle ToDo updates |
| 125 | + handleToDoUpdate = (snapshot) => { |
| 126 | + this.todos = snapshot.val() || {}; |
| 127 | + |
| 128 | + this.setState({ |
| 129 | + todos: this.listView.cloneWithRows(this.todos), |
| 130 | + }); |
| 131 | + } |
| 132 | + |
| 133 | + // Add a new ToDo onto Firebase |
| 134 | + // If offline, this will still trigger an update to handleToDoUpdate |
| 135 | + addToDo() { |
| 136 | + firestack.database() |
| 137 | + .ref('users/1234/todos') |
| 138 | + .set({ |
| 139 | + ...this.todos, { |
| 140 | + name: 'Yet another todo...', |
| 141 | + complete: false, |
| 142 | + }, |
| 143 | + }); |
| 144 | + } |
| 145 | + |
| 146 | + // Render a ToDo row |
| 147 | + renderToDo(todo) { |
| 148 | + // Dont render the todo if its complete |
| 149 | + if (todo.complete) { |
| 150 | + return null; |
| 151 | + } |
| 152 | + |
| 153 | + return ( |
| 154 | + <View> |
| 155 | + <Text>{todo.name}</Text> |
| 156 | + </View> |
| 157 | + ); |
| 158 | + } |
| 159 | + |
| 160 | + // Render the list of ToDos with a Button |
| 161 | + render() { |
| 162 | + return ( |
| 163 | + <View> |
| 164 | + <ListView |
| 165 | + dataSource={this.state.todos} |
| 166 | + renderRow={(...args) => this.renderToDo(...args)} |
| 167 | + /> |
| 168 | + |
| 169 | + <Button |
| 170 | + title={'Add ToDo'} |
| 171 | + onPress={() => this.addToDo} |
| 172 | + /> |
| 173 | + <View> |
| 174 | + ); |
| 175 | + } |
| 176 | +``` |
| 177 | +
|
| 178 | +#### Differences between `.on` & `.once` |
| 179 | +
|
| 180 | +With persistence enabled, any calls to a ref with `.once` will always read the data from disk and not contact the server. |
| 181 | +On behavious differently, by first checking for a connection and if none exists returns the persisted data. If it successfully connects |
| 182 | +to the server, the new data will be returned and the disk data will be updated. |
0 commit comments