Статьи

Создание приложения для создания заметок с помощью React и Flux

React от Facebook — очень хорошая библиотека для создания пользовательских интерфейсов. Единственная проблема в том, что React не волнует, как ваше приложение обрабатывает данные. Большинство людей используют React как V в MV *. Итак, Facebook представил шаблон под названием Flux, который обеспечивает функциональный подход к обработке данных в приложении. В этом руководстве дается краткое представление о шаблоне Flux и показано, как создать приложение для создания заметок с использованием архитектуры React и Flux.

Учебник для начинающих на Flux

Flux опирается на однонаправленный поток данных. У нас есть два ключевых компонента в шаблоне Flux:

  1. Магазины : Компонент магазина, как следует из названия, хранит данные приложения.
  2. Действия : новые данные поступают в хранилище посредством действий. Магазины слушают действия и выполняют некоторые задачи (например, изменяют данные), когда действия вызываются. Это сохраняет поток данных однонаправленным.

Чтобы укрепить концепцию, давайте возьмем пример из реального мира. Например, в приложении для создания заметок у вас может быть следующее расположение:

  1. Магазин под названием NoteStore котором хранится список заметок.
  2. Вы можете иметь действие под названием createNote . Магазин NoteStore прослушивает действие createNote и обновляет свой список новой заметкой при каждом createNote действия. Данные поступают в хранилище только через действия.
  3. NoteStore запускает событие всякий раз, когда его данные изменяются. Ваш компонент React, скажем, NoteListComponent , прослушивает это событие и обновляет список заметок, представленных в представлении. Вот как данные поступают из хранилища.

Итак, поток данных можно визуализировать следующим образом:

Data Flow Diagram

Самым большим преимуществом шаблона Flux является то, что он сохраняет данные вашего приложения плоскими. Поскольку мутация может быть осуществлена ​​только с помощью действий, легче понять, как изменение данных влияет на все приложение.

Замечания:

Если вы просмотрели руководство Facebook по Flux , вы могли заметить концепцию Dispatcher. Диспетчер — это реестр обратных вызовов в магазины. Когда действие вызывается, диспетчер отвечает на него и отправляет связанные данные во все зарегистрированные хранилища. Затем магазины проверяют тип действия и выполняют задачи соответственно.

Вышеуказанный процесс был значительно упрощен библиотекой под названием Reflux . Это устраняет концепцию диспетчера, делая действия прослушиваемыми. Так, в магазинах Reflux можно напрямую прослушивать действия и отвечать на их вызовы.

Чтобы полностью понять паттерн Flux, давайте создадим простое приложение для создания заметок с Reflux, React и Node.js.

Настройка среды разработки

Мы будем использовать React и Reflux в качестве Node-модулей и использовать Browserify, чтобы сделать их доступными и на стороне клиента. Итак, вот как мы настраиваем среду:

  1. Мы будем использовать Browserify для объединения наших компонентов React, Actions и Stores в клиентский пакет .js .
  2. Мы будем использовать grunt watch для обнаружения изменений в вышеперечисленных компонентах и ​​повторного запуска Browserify при каждом изменении.
  3. grunt nodemon используется для перезапуска сервера всякий раз, когда .jsx какой-либо файл .jsx или .js чтобы вам не приходилось делать это вручную.

Вы можете скачать код с GitHub и открыть Gruntfile.js чтобы прочитать о задачах. Если у вас есть репозиторий на вашем компьютере, вы можете просто запустить npm install для установки необходимых узловых модулей. Запустите следующие команды и начните разработку:

 grunt watch grunt nodemon 

Приложение доступно по адресу http://localhost:8000 и работает следующим образом:

Работа над приложением

Давайте начнем с различных компонентов приложения. Вот как мы можем разделить наш пользовательский интерфейс на различные компоненты:

Application Components

Вот что делает каждый компонент:

  1. NoteApp : это корневой компонент, который состоит из двух дочерних компонентов: NoteListBox и NoteCreationBox .
  2. NoteListBox : имеет единственный дочерний компонент NoteList . Он извлекает список заметок из Flux Store и передает их в NoteList .
  3. NoteList : отвечает за отображение каждого компонента Note . Передает объект заметки каждому компоненту Note .
  4. Note . Отображает сведения об одном элементе заметки. В этом случае мы просто отображаем title . Вы можете легко перейти и показать другие детали, такие как date , subtitle и т. Д.
  5. NoteCreationBox : этот компонент визуализирует компонент TextArea и передает ему отредактированный в настоящее время id заметки, если таковой имеется.
  6. TextArea : Предоставляет textarea для принятия ввода пользователя. NoteCreationBox текст заметки в NoteCreationBox для сохранения.

Создание действий

Давайте использовать Reflux для создания некоторых действий. Если вы откроете actions/NoteActions.js , вы увидите, как создаются действия. Вот фрагмент:

 var Reflux = require('reflux'); var NoteActions = Reflux.createActions([ 'createNote', 'editNote' ]); module.exports = NoteActions; 

Reflux.createActions используется для создания действий. Мы экспортируем эти Действия, чтобы использовать их в наших компонентах.

Создание магазина

У нас есть одно хранилище под названием NoteStore которое поддерживает массив заметок. Следующий код используется для создания магазина ( stores/NoteStore.js ):

 var Reflux = require('reflux'); var NoteActions = require('../actions/NoteActions'); var _notes = []; //This is private notes array var NoteStore = Reflux.createStore({ init: function() { // Here we listen to actions and register callbacks this.listenTo(NoteActions.createNote, this.onCreate); this.listenTo(NoteActions.editNote, this.onEdit); }, onCreate: function(note) { _notes.push(note); //create a new note // Trigger an event once done so that our components can update. Also pass the modified list of notes. this.trigger(_notes); }, onEdit: function(note) { // Update the particular note item with new text. for (var i = 0; i < _notes.length; i++) { if(_notes[i]._id === note._id) { _notes[i].text = note.text; this.trigger(_notes); break; } } }, //getter for notes getNotes: function() { return _notes; }, //getter for finding a single note by id getNote: function(id) { for (var i = 0; i < _notes.length; i++) { if(_notes[i]._id === id) { return _notes[i]; } } } }); module.exports = NoteStore; //Finally, export the Store 

Как видите, мы слушаем два действия, createNote и editNote , внутри метода init . Мы также регистрируем обратные вызовы для выполнения при вызове действий. Код для добавления / обновления заметки довольно прост. Мы также выставляем геттеры для получения списка заметок. Наконец, магазин экспортируется, чтобы его можно было использовать в нашем компоненте.

Создание компонентов

Все наши компоненты React находятся в каталоге react/components . Я уже показал общую структуру пользовательского интерфейса. Вы можете проверить загруженный исходный код, чтобы узнать больше о каждом компоненте. Здесь я покажу вам ключевую вещь (т.е. как наши компоненты вызывают действия и взаимодействуют с магазином).

NoteListBox:

Этот компонент получает список заметок из NoteStore и NoteStore их в компонент NoteList который затем отображает заметки. Вот как выглядит компонент:

 var React = require('react'); var NoteList = require('./NoteList.jsx'); var NoteStore = require('../../stores/NoteStore'); var NoteListBox = React.createClass({ getInitialState: function() { return { notes: NoteStore.getNotes() }; }, onChange: function(notes) { this.setState({ notes: notes }); }, componentDidMount: function() { this.unsubscribe = NoteStore.listen(this.onChange); }, componentWillUnmount: function() { this.unsubscribe(); }, render: function() { return ( <div className="col-md-4"> <div className="centered"><a href="" onClick={this.onAdd}>Add New</a></div> <NoteList ref="noteList" notes={this.state.notes} onEdit={this.props.onEdit} /> </div> ); } }); module.exports = NoteListBox; 

Когда компонент монтируется, мы начинаем слушать событие change в NoteStore . Это передается всякий раз, когда есть мутация в списке заметок. Наш компонент прослушивает это событие, чтобы он мог повторно визуализировать заметки в случае каких-либо изменений. Следующая строка регистрирует слушателя:

 this.unsubscribe = NoteStore.listen(this.onChange); 

Таким образом, всякий раз, когда происходит изменение, onChange метод компонента onChange . Этот метод получает обновленный список заметок и изменяет состояние.

 this.setState({ notes: notes //state changes }); 

Поскольку this.state.notes передается в качестве prop в NoteList , всякий раз, когда изменяется состояние, NoteList перерисовывает себя.

Наконец, мы пишем this.unsubscribe() внутри componentWillUnmount для удаления слушателя.

Таким образом, вот как NoteList всегда обновляется, прослушивая событие change Store. Теперь давайте посмотрим, как создается / редактируется заметка.

NoteCreationBox:

Взгляните на следующий метод NoteCreationBox :

 handleSave: function(noteText, id) { if (id) { NoteActions.editNote({ _id: id, text: noteText }); } else { NoteActions.createNote({ _id: Date.now(), text: noteText }); } } 

Этот метод вызывается всякий раз, когда нажимается кнопка «Сохранить». Он принимает noteText качестве первого параметра. Если в качестве второго параметра передается id , мы знаем, что это операция редактирования, и вызываем действие NoteActions.editNote() . В противном случае мы генерируем id для новой заметки и вызываем NoteActions.createNote() . Помните, что наш NoteStore слушает эти действия. В зависимости от действия выполняется соответствующий обратный вызов магазина. Как только данные видоизменены, хранилище запускает событие изменения, и наш компонент NoteList обновляется сам.

Именно так данные поступают в систему и затем отправляются в приложении на основе Flux.

Зачем использовать React на сервере

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

Я призываю вас пройтись по исходному коду и улучшить его, так как есть много возможностей для улучшений. Если у вас есть какие-либо вопросы, дайте мне знать в комментариях.

Спасибо за прочтение!