Ember vs React - the ultimate battle (Round 2)

Richard Thompson
10 min readJul 23, 2018

--

So, in the previous article we built and connected the components up so that we had a simple Movie List app for both React and Ember. In this article we will be hooking the apps up to Firebase. Firebase is a real time database which can be used with relative ease.

If you want to take a sneak peak at the final repositories, here they are for the React and Ember projects.

Routes

React

In React data loading isn’t definitively linked to routes. Data loading would would take place in the componentDidMount lifecycle method of a React component. This project is so basic that we did not use react-router for routing. If we were to make the project more complicated we could for example, have used a separate route for adding movies to the database.

Ember

Ember is router-centric, meaning that routes are key to building apps. In the Ember app we made an application route to place the landing-page component. A small point to make is that you would not place components like we have in the application route, but for the sake of simplicity and demo purposes we have done.

With Ember when you generate routes they come with a template.hbs, controller.js and a route.js. A quick side note the pod flag will group the route, controller and the template file in a folder which matches the name of the route rather than putting the template in the templates folder and putting the route in the routes folder. It’s a nicer and neater way to organise the code. In addition to the route being generated, the route will be added to the router.js file where all the routes are defined:

// app/router.jsimport Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
//this.route('home');
});
export default Router;

The application route isn’t defined as it doesn’t generate a route definition in the router.js. Don’t worry about the config for now, this is out of the scope of this article. Essentially all the routes would be defined within the Router.map function.

Models and Controllers

In React the state would be where the data lives (either locally or centrally managed) and in Ember the data lives in the store and the models provide structure. Controllers are not shipped with the React library but are shipped with the Ember framework.

Before we continue we need to make a model called movie:

ember generate model movie title:string description:string image:string

This will generate a model which represents the movies data in our application. So if we want to grab data from the model we interact with the store. With react the application data lives in the state not models.

In the route file you can add the following code:

// app/application/route.jsimport Route from '@ember/routing/route';export default Route.extend({
model() {
return this.store.query('movie', {
orderBy: 'title',
});
}

});

So we have used the model hook and inside this we have accessed the store. Ember comes with a package called ember-data, which is a fully-fledged data persistence layer for Ember applications. I’m not going to go into an in-depth explanation as it’s a bit out of the scope of this article, but it’s as easy as defining a model, then using the store to perform create/read/update/delete (CRUD) operations for that model against your configured data source, in our case Firebase’s real time database.

In Ember we fetch our data in the route file, and we handle user interactions from the corresponding controller. So lets make an application controller to handle when a movie is added:

ember generate controller application --pod

In the controller.js file for the application route copy and paste the following code:

// app/application/controller.jsimport Controller from '@ember/controller';export default Controller.extend({
actions: {
addMovie(title, description, image) {
const newMovie = this.store.createRecord('movie', {
title,
description,
image
});
newMovie.save();
}
},
});

We have now defined actions on the application route’s controller and defined the model hook on the route.js file . By convention, the return value for the model hook is available as model in the route’s template. We can now pass this action and model down to components in the application route’s template file:

//app/application/template.hbs{{landing-page
add=(action 'addMovie')
movies=model
}}

And add the properties below on the component.js file for the landing-page:

import Component from '@ember/component';export default Component.extend({  add:null,  movies:null

});

There are some similarities between Redux actions (a package for managing state in React apps) being dispatched to alter state and the actions here that modify data via the store and models. In Ember the flux-like pattern is referred to as DDAU — data-down, actions-up.

In the landing-page template where we defined the movie-list and add-movie-form we can now pass the model data to the movie-list component and the add action to the add-movie-form component:

// app/components/landing-page/template.hbs{{movie-list-header}}{{movie-list
movies=movies
}}
{{add-movie-form
add=add
}}

And for the add-movie-form component.js file copy and paste the following code:

// app/components/add-movie-form/component.jsimport Component from '@ember/component';export default Component.extend({
tagName: 'form',
classNames: ['add-movie-form'],
title: null,
image: null,
description: null,
add:null,submit (event) {
event.preventDefault();
this.get('add')(this.get('title'), this.get('description'),
this.get('image'));
this.setProperties({'title': null, 'image': null, 'description':
null});
}

});

Firebase

So at the minute we don’t have any data or backend to store the data and have persistence. So I know this is overkill for a simple app but I’m going to setup Firebase to show you how you how different it is in the Ember and React apps.You will need to create a Firebase account if you don’t have one already, don’t worry it has a free tier. So go to the console and you should see something like this:

I already have a movie-list created for the React app. But go ahead and create a new project and give it a name. When created click on your project, then click on database on the left hand side, click on realtime database and start in test mode:

Click on the overview page and then ‘Add firebase to your web app’:

React

With React and setting up Firebase, carry out the below command to install Firebase into the project:

npm install -S firebase

Add the following code to the firebase.js file in the folder src with your details in the empty strings from the ‘Add firebase to your web app’ section:

// src/firebase.jsimport firebase from 'firebase';const config = {
apiKey: '',
authDomain: '',
databaseURL: '',
projectId: '',
storageBucket: '',
messagingSenderId: ''
};
firebase.initializeApp(config);export default firebase;

Below shows the AddMovieForm component, add the following code:

// src/components/form/AddMovieForm.jsimport React, { Component } from 'react';
import './addMovieForm.css';
import firebase from '../../firebase.js';
class AddMovieForm extends Component {
constructor(props) {
super(props);
this.state = {
title: '',
description:'',
image:''
};
this.handleChange = this.handleChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
render() {
return (
<form onSubmit={this.onSubmit} className='movie-form'>
<input
name='title'
value={this.state.title}
onChange={this.handleChange}
placeholder='title..'
required
/>
<input
name='description'
value={this.state.description}
onChange={this.handleChange}
placeholder='description..'
required
/>
<input
name='image'
value={this.state.image}
onChange={this.handleChange}
placeholder='image..'
required
/>
<button type='submit'>Add Movie</button>
</form>
);
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
onSubmit (event) {
event.preventDefault();
const movies = firebase.database().ref('movies'); const movie = {
title: this.state.title,
description: this.state.description,
image: this.state.image
};
movies.push(movie); this.setState({
title:'',
description:'',
image:''
});

}
}
export default AddMovieForm;

Now if you add movies into your form and go over to the Firebase database you should see what you have entered into the form. This is considerably different to Ember in that you don’t interact with models in React, you interact with Firebase by sending data directly to Firebase.

The next part of the React app is to display the data. Go back to the MovieList.js component file in the react app, copy and paste the following code:

// src/components/movie-list/MovieList.jsimport React, { Component } from 'react';
import './movieList.css';
import MovieListItem from '../movie-list-item/MovieListItem';
import firebase from '../../firebase.js';
class MovieList extends Component {
constructor(props) {
super(props);
this.state = {
movies:[]
};
}
componentDidMount () {
const itemsRef = firebase.database().ref('movies');
itemsRef.on('value', (snapshot) => {
// Due to firebase database storing data in objects with keys
// we need to grab the values from the movies snapshot object,
// hence using
Object.values below.
const movies = Object.values(snapshot.val()) this.setState({
movies
});
});
}

render() {
return (
<div className='movie-list'>
{this.state.movies.map((movie, i) => {
return(
<MovieListItem movie={movie} key={i}/>
)
})}
</div>
);
}
}
export default MovieList;

Looking at the above code in the componentDidMount lifecycle method you can see it’s slightly more complicated than putting a model hook on the application controller in the Ember app and just interacting with the ember-data store. Here you have to deal with the Firebase API and manipulate the snapshot object Firebase provides. As we will see below in Ember it’s simpler. This is a key point to remember is although Ember has quite a lot of tools, a large API and a steeper learning curve, there are a lot of packages which abstract out tasks/interactions.

Ember

In the Ember app you would use an adapter which abstracts out all the interactions with the Firebase servers.

First things first we will need to install the emberfire adapter. So go to the root of your Ember project and type the following into the command line:

ember install emberfire

Create another project on Firebase for the Ember app and copy the Firebase object, create a firebase.js file in the config folder:

// config/firebase.jsmodule.exports = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: ""
};

Now go to your ember config folder and go in the environment.js file and import the Firebase object and place it as below:

'use strict';
const firebase = require('./firebase');
module.exports = function(environment) {
var ENV = {
modulePrefix: 'movie-list',
environment: environment,
rootURL: '/',
locationType: 'auto',
EmberENV: {
FEATURES: {
// Here you can enable experimental features on an ember canary build
// e.g. 'with-controller': true
}
},
APP: {
// Here you can pass flags/options to your application instance
// when it is created
},
firebase
};
if (environment === 'development') {
//...

And its that simple. If you remember we created actions on the application controller:

// app/application/controller.jsimport Controller from '@ember/controller';export default Controller.extend({
actions: {
addMovie(title, description, image) {
const newMovie = this.store.createRecord('movie', {
title,
description,
image
});
newMovie.save();
}
},
});

We interact with the store and find or delete records, without having to directly interact with the firebase API, or having any code which is specific to storing the data in firebase. So when you add a record to the store it will automatically add it to your firebase database under the movie collection.

Which Framework Wins?

So, you should have a fair idea for yourself about the differences after building both these little apps.

Routes are integral to Ember and with React there is less emphasis on routes and more on composing components together and reusing components. React tends to need more setup and this is by design of the library, there are many ways of setting up a project and this provides incredible flexibility. Where as Ember is more rigid and opinionated in the way you should carry things out.

Ember has ember-data and models, ember-data makes it super easy to interact with the store and grab data from the models. React on the other hand has local state where data lives and if you chose, Redux or flux, two incredibly popular state management patterns.

So which one would I choose? It’s not a straight one or the other for me. It’s like comparing a mac with a windows computer, a lot of it comes down to preference and suitability. Ember is a framework and is designed to have consistent architecture when applications scale up and become more complicated. React has a smaller API with less built in functionality and relies more on the ecosystem when you want to put architecture in place to manage complex applications.

A key difference is that ember can abstract things out, for example the firebase adapter abstracts out all the interactions with the firebase API. Where as in React you can get more down and dirty with interacting with API’s, or if you so chose you can install packages that can enforce a more traditional MVC framework.

From the perspective of a junior developer, however, React is a lot easier to learn and get to grips with. You can build incredibly interactive apps with great user experiences very quickly. Ember can build just as good apps but has a steeper learning curve and enforces a lot more rules on the way you do things. That being said, when you get to grips with the way Ember works… utilising adapters, add-ons and generating boilerplate code is so much easier.

I find I can’t quite come down on one side of the fence or the other — what do you think? Feel free to add your comments below about your experience of Ember vs React. It would be great to hear about other people’s experiences of the two frameworks.

Here’s the final repositories for the React and Ember apps.

--

--

Richard Thompson

Frontend Developer- a tech Enthusiast who uses React and Ember.