Blog

How to Use Backendless with ReactJS (Part 3)

by on April 3, 2019

How to Use Backendless with ReactJS
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.

What is Real-Time (RT) database?

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:

  • create – this event is delivered to the client app when a new object is created on the server
  • update – this event is delivered to the client app when an existing object is changed on the server
  • delete – this event is delivered to the client app when an existing object is deleted on the server

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.

Subscribe for Real-Time (RT) changes

Generally, to have up-to-date data, we need three subscriptions/listeners as mentioned above:

  • Listener to create record in the database
  • Listener to update record in the database
  • Listener to delete record in the database

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:

  • Reducer action t.CREATE_PERSON_SUCCESS will put the newly created person into the store
  • RT action t.ON_PERSON_CREATE will put the newly created person into the store as well.

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 JS-SDK module
  • Import RT actions
  • Modify componentWillMount method
  • Add componentWillUnmount method
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);

Real-Time Demo

Time to take it for a test drive. Let’s see how it works:
Backendless real-time database in a reactjs app

Conclusion

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.

Leave a Reply