Итак, в предыдущей статье мы создали и соединили компоненты так, чтобы у нас было простое приложение Movie List как для React, так и для Ember. В этой статье мы будем подключать приложения к Firebase. Firebase - это база данных в реальном времени, которую можно относительно легко использовать.

Если вы хотите заглянуть в финальные репозитории, вот они для проектов React и Ember.

Маршруты

Реагировать

В React загрузка данных не связана окончательно с маршрутами. Загрузка данных будет происходить в componentDidMount методе жизненного цикла компонента React. Этот проект настолько прост, что мы не использовали react-router для маршрутизации. Если бы мы усложнили проект, мы могли бы, например, использовать отдельный маршрут для добавления фильмов в базу данных.

Ember

Ember ориентирован на маршрутизатор, а это означает, что маршруты являются ключом к созданию приложений. В приложении Ember мы создали маршрут приложения для размещения компонента landing-page. Небольшой момент, который следует отметить, заключается в том, что вы не должны размещать компоненты, как у нас, в маршруте приложения, а для простоты и демонстрационных целей, которые мы сделали.

С Ember, когда вы генерируете маршруты, они имеют template.hbs, controller.js и route.js. Небольшое примечание: флаг pod сгруппирует маршрут, контроллер и файл шаблона в папке, которая соответствует имени маршрута, а не помещает шаблон в папку шаблонов и помещает маршрут в маршруты. папка. Это более приятный и аккуратный способ организовать код. Помимо генерируемого маршрута, он будет добавлен в файл router.js, где определены все маршруты:

// app/router.js
import 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 router.js. Пока не беспокойтесь о конфигурации, это выходит за рамки данной статьи. По сути, все маршруты будут определены в функции Router.map.

Модели и контроллеры

В React состояние будет там, где данные находятся (локально или централизованно управляются), а в Ember данные находятся в хранилище, а модели обеспечивают структуру. Контроллеры не поставляются с библиотекой React, но поставляются с фреймворком Ember.

Прежде чем мы продолжим, нам нужно создать модель с именем movie:

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

Это сгенерирует модель, которая представляет данные фильмов в нашем приложении. Итак, если мы хотим получить данные из модели, мы взаимодействуем с магазином. С response данные приложения живут в состоянии, а не модели.

В файл маршрута вы можете добавить следующий код:

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

Итак, мы использовали крючок модели и внутри него мы получили доступ к магазину. Ember поставляется с пакетом ember-data, который представляет собой полноценный уровень сохранения данных для приложений Ember. Я не собираюсь вдаваться в подробное объяснение, поскольку это немного выходит за рамки данной статьи, но это так же просто, как определение модели, а затем использование хранилища для создания / чтения / обновления / удаления (CRUD) операции для этой модели с вашим настроенным источником данных, в нашем случае с базой данных Firebase в реальном времени.

В Ember мы извлекаем наши данные из файла маршрута и обрабатываем действия пользователя с соответствующего контроллера. Итак, давайте сделаем контроллер приложения для обработки при добавлении фильма:

ember generate controller application --pod

В файле controller.js для маршрута приложения скопируйте и вставьте следующий код:

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

Теперь мы определили действия в контроллере маршрута приложения и определили обработчик модели для файла route.js. По соглашению возвращаемое значение для хука модели доступно как model в шаблоне маршрута. Теперь мы можем передать это действие и модель компонентам в файле шаблона маршрута приложения:

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

И добавьте свойства ниже в component.js file для landing-page:

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

Есть некоторое сходство между действиями Redux (пакет для управления состоянием в приложениях React), отправляемыми для изменения состояния, и действиями, которые изменяют данные через хранилище и модели. В Ember подобный потоку паттерн называется DDAU - data-down, actions-up.

В шаблоне landing-page, где мы определили movie-list и add-movie-form, теперь мы можем передать данные модели компоненту movie-list, а действие add - компоненту add-movie-form :

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

А для файла формы добавления фильма component.js скопируйте и вставьте следующий код:

// app/components/add-movie-form/component.js
import 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

Таким образом, в настоящий момент у нас нет данных или серверной части для хранения данных и сохранения данных. Итак, я знаю, что это перебор для простого приложения, но я собираюсь настроить Firebase, чтобы показать вам, насколько он отличается в приложениях Ember и React. Вам нужно будет создать учетную запись Firebase, если у вас ее еще нет. , не волнуйтесь, у него есть бесплатный уровень. Зайдите в консоль, и вы должны увидеть что-то вроде этого:

У меня уже есть movie-list, созданный для приложения React. Но давайте, создайте новый проект и дайте ему имя. После создания щелкните свой проект, затем щелкните базу данных слева, щелкните базу данных в реальном времени и запустите в тестовом режиме:

Нажмите на страницу обзора и выберите «Добавить firebase в свое веб-приложение»:

Реагировать

С помощью React и настройки Firebase выполните следующую команду, чтобы установить Firebase в проект:

npm install -S firebase

Добавьте следующий код в firebase.js файл в папке src, указав свои данные в пустых строках из раздела «Добавить firebase в свое веб-приложение»:

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

Ниже показан компонент AddMovieForm, добавьте следующий код:

// src/components/form/AddMovieForm.js
import 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;

Теперь, если вы добавите фильмы в свою форму и перейдете к базе данных Firebase, вы увидите, что вы ввели в форму. Это значительно отличается от Ember тем, что вы не взаимодействуете с моделями в React, вы взаимодействуете с Firebase, отправляя данные непосредственно в Firebase.

Следующая часть приложения React - отображение данных. Вернитесь к файлу компонента MovieList.js в приложении реакции, скопируйте и вставьте следующий код:

// src/components/movie-list/MovieList.js
import 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;

Глядя на приведенный выше код в методе жизненного цикла componentDidMount, вы можете увидеть, что это немного сложнее, чем привязка модели к контроллеру приложения в приложении Ember и простое взаимодействие с хранилищем ember-data. Здесь вам нужно иметь дело с API Firebase и управлять объектом моментального снимка, который предоставляет Firebase. Как мы увидим ниже, в Ember все проще. Это ключевой момент, о котором следует помнить: хотя у Ember довольно много инструментов, большой API и более крутая кривая обучения, существует множество пакетов, которые абстрагируют задачи / взаимодействия.

Ember

В приложении Ember вы должны использовать адаптер, который абстрагирует все взаимодействия с серверами Firebase.

Перво-наперво нам нужно установить адаптер emberfire. Итак, перейдите в корень вашего проекта Ember и введите в командную строку следующее:

ember install emberfire

Создайте еще один проект на Firebase для приложения Ember и скопируйте объект Firebase, создайте файл firebase.js в папке config:

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

Теперь перейдите в папку конфигурации ember, перейдите в файл environment.js, импортируйте объект Firebase и поместите его, как показано ниже:

'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') {
//...

И это так просто. Если вы помните, мы создали действия на контроллере приложения:

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

Мы взаимодействуем с хранилищем и находим или удаляем записи, не имея необходимости напрямую взаимодействовать с API firebase или иметь какой-либо код, специфичный для хранения данных в firebase. Поэтому, когда вы добавляете запись в хранилище, она автоматически добавляется в вашу базу данных firebase в коллекцию фильмов.

Какой фреймворк побеждает?

Итак, вы должны иметь четкое представление о различиях после создания обоих этих небольших приложений.

Маршруты являются неотъемлемой частью Ember, и в React меньше внимания уделяется маршрутам и больше - объединению компонентов и их повторному использованию. React, как правило, требует дополнительной настройки, и это обусловлено дизайном библиотеки, существует множество способов настройки проекта, и это обеспечивает невероятную гибкость. В то время как Ember более жесткий и упрямый в том, как вы должны действовать.

В Ember есть ember-data и модели, ember-data упрощает взаимодействие с хранилищем и извлечение данных из моделей. React, с другой стороны, имеет локальное состояние, в котором находятся данные, и, если хотите, Redux или flux, два невероятно популярных шаблона управления состоянием.

Итак, что бы я выбрал я? Для меня это не одно и то же. Это все равно, что сравнивать Mac с компьютером с Windows, во многом это зависит от предпочтений и пригодности. Ember - это фреймворк, который спроектирован так, чтобы иметь согласованную архитектуру при масштабировании и усложнении приложений. React имеет меньший API с меньшей встроенной функциональностью и больше полагается на экосистему, когда вы хотите внедрить архитектуру для управления сложными приложениями.

Ключевое отличие состоит в том, что ember может абстрагироваться, например, адаптер firebase абстрагирует все взаимодействия с API firebase. Где, как в React, вы можете усложнить взаимодействие с API или, если хотите, вы можете установить пакеты, которые могут обеспечить более традиционную структуру MVC.

Однако с точки зрения младшего разработчика React намного проще изучить и освоить. Вы можете очень быстро создавать невероятно интерактивные приложения с отличным пользовательским интерфейсом. Ember может создавать такие же хорошие приложения, но у него более крутая кривая обучения и гораздо больше правил для ваших действий. При этом, когда вы понимаете, как работает Ember ... использование адаптеров, надстроек и создание шаблонного кода становится намного проще.

Я обнаружил, что не могу спуститься по одну сторону забора - что вы думаете? Не стесняйтесь добавлять ниже свои комментарии о своем опыте работы с Ember vs React. Было бы здорово услышать об опыте других людей с этими двумя фреймворками.

Вот последние репозитории приложений React и Ember.