This is the third part of our series on using Backendless with a ReactJS frontend app. You can catch up on the previous articles here: Part 1 and Part 2. If you’d like to jump in now, you can simply create a new Backendless app, clone our previous progress from our Github.com repository, and use this commit as an entry point for today’s article.
Our goal for today is to showcase integration with our Real-Time (we call it RT) database for delivering changes in your data table from the server to the client. We have previously written about the implementation of RT in an Angular app (“How to Use the Backendless Real-Time Database in Your Angular App”). If you’re interested in Angular or you just want to see the difference between the usage of RT with React and Angular, we’d recommend you give that article a read.
As discussed in our Angular series, in most cases, you want your application to display the most up-to-date data without any additional requests to the server. There are three events that, once they occur, sync your client’s app with the server data:
All of our SDKs (JavaScript, Android, and iOS) have been updated with the logic necessary to establish a connection to our Real-Time servers and provide you with the ability to subscribe to the events shown above.
Check out the Real-Time Database API documentation for more information.
Generally, to have up-to-date data, we need three subscriptions/listeners as mentioned above:
Also, there may be a case when we need to listen for only one kind of change. For example, let’s say we have a Messages table and we know that there is no way to remove or update records on the server. Therefore, we only need to subscribe to create objects. As another example, say we have a Users table and we would only like to receive changes to current users. In this case, we need only the subscription for the update object.
In our app, we will use all of the subscription types in order to keep our Persons collection up-to-date.
As you know from the previous articles in this series, we use Redux for our app data store. In order to deliver changes from the server to the redux store, we need to have three additional actions for each RT subscription. Let’s create them in ./src/store/actions/persons.js:
export const onPersonCreate = person => ({ person, type: t.ON_PERSON_CREATE, }); export const onPersonUpdate = person => ({ person, type: t.ON_PERSON_UPDATE, }); export const onPersonRemove = person => ({ person, type: t.ON_PERSON_REMOVE, });
Don’t forget to add action types for these actions.
Now we are going to add reducers for the above actions, but before we do that, we have to look out for a duplication issue. As we’ve already implemented reducers for changing the store when we create/update/delete persons, and now we’re going to add RT actions, we will see duplication of persons in the store. For example, when we create a new person:
To avoid this scenario, we should adjust the Persons reducers. Let’s replace the current code in ./src/store/reducers/persons.js with the following:
import t from '../action-types' import { reduceReducers, loadReducer, reducersMap } from './helpers' const initialState = { list: [] }; const personsReducer = reduceReducers(initialState, loadReducer(t.LOAD_PERSONS, (state, action) => ({ ...state, list: action.result })), reducersMap({ [t.CREATE_PERSON_SUCCESS]: (state, action) => addPerson(state, action.result), [t.UPDATE_PERSON_SUCCESS]: (state, action) => updatePerson(state, action.result), [t.REMOVE_PERSON_SUCCESS]: (state, action) => deletePerson(state, action.personId), [t.ON_PERSON_CREATE]: (state, action) => addPerson(state, action.person), [t.ON_PERSON_UPDATE]: (state, action) => updatePerson(state, action.person), [t.ON_PERSON_REMOVE]: (state, action) => deletePerson(state, action.person.objectId) }) ); function addPerson(state, person) { if (state.list.find(p => p.objectId === person.objectId)) { return state } return { ...state, list: state.list.concat(person) } } function updatePerson(state, person) { return { ...state, list: state.list.map(p => p.objectId === person.objectId ? person : p) } } function deletePerson(state, personId) { return { ...state, list: state.list.filter(person => person.objectId !== personId) } } export default personsReducer
Finally today, let’s add RT subscriptions in the ./src/persons/index.js file. To do so:
import Backendless from 'backendless'; import { loadPersons, getPersons, onPersonCreate, onPersonUpdate, onPersonRemove } from '../store';
componentWillMount(){ this.props.loadPersons(); this.personRT = Backendless.Data.of('Person').rt(); this.personRT.addCreateListener(this.props.onPersonCreate); this.personRT.addUpdateListener(this.props.onPersonUpdate); this.personRT.addDeleteListener(this.props.onPersonRemove); } componentWillUnmount(){ this.personRT.removeCreateListener(this.props.onPersonCreate); this.personRT.removeUpdateListener(this.props.onPersonUpdate); this.personRT.removeDeleteListener(this.props.onPersonRemove); }
export default connect(mapStateToProps, { loadPersons, onPersonCreate, onPersonUpdate, onPersonRemove })(Persons);
Time to take it for a test drive. Let’s see how it works:
Surprisingly easy, wasn’t it? We just used a very basic case, but there are many cases where RT could be vital. If you have any questions or are looking for a specific solution with RT, please leave us a comment or create a new support topic on our support forum. Thanks for reading! Everything we have done today can be found in this commit.