Я работал над приложением из учебной программы FreeCodeCamp и подумал, что другим оно может показаться интересным. В этой статье вы можете прочитать полную документацию по процессу сборки. Наслаждаться!

«Неудача - не обязательно зло. На самом деле это совсем не зло. Это необходимое следствие того, чтобы делать что-то новое ».

- Эд Кэтмелл

Соревнование

Для этой конкретной задачи мне пришлось создать приложение, которое позволяло бы отслеживать различные акции. Подробнее о полном испытании вы можете прочитать здесь. А теперь приступим.

Пользовательские истории довольно просты:

  • Я могу просматривать график, отображающий последние линии тренда для каждой добавленной акции.
  • Я могу добавлять новые акции по названию их символа.
  • Могу убрать косяки.
  • Я могу видеть изменения в режиме реального времени, когда любой другой пользователь добавляет или удаляет акции. Для этого вам нужно будет использовать WebSockets.

Это выглядит так:

Дорожная карта

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

Вот план, который я использовал:

  1. Настройте среду с помощью create-react-app
  2. Изложите базовую структуру компонентов React
  3. Настроить экосистему Redux
  4. Работайте со всеми компонентами, разделите их на компоненты контейнера и подключите все к хранилищу Redux.
  5. Создайте компонент диаграммы с помощью React-Vis
  6. Создайте бэкэнд с помощью socket.io
  7. Адаптируйте интерфейс к WebSockets
  8. Развернуть на Heroku

Внешний интерфейс

Я собираюсь выделить ключевые моменты - это не пошаговое руководство.

Настройка с помощью пакета create-response-app

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

По сути, он обеспечивает среду, которая:

  • Поддержка синтаксиса React, JSX, ES6 и Flow.
  • Предоставляет языковые дополнительные возможности помимо ES6, такие как оператор распространения объекта.
  • Имеет сервер разработки, который ищет распространенные ошибки.
  • Импортирует файлы CSS и изображений прямо из JavaScript.
  • Имеет автоматические префиксы CSS, поэтому вам не нужны префиксы -webkit или другие префиксы.
  • Имеет сценарий сборки для объединения JS, CSS и изображений для производства с картами исходных текстов.
  • Предоставляет вам работника службы, работающего в автономном режиме, и манифест веб-приложения, отвечающий всем критериям Progressive Web App.

Довольно рано мне пришлось извлечь конфигурацию (= открыть конфигурацию среды для изменений), чтобы изменить конфигурацию WebPack.

Проблема заключалась в том, что я хотел добавить jQuery для Materializecss - и всегда были проблемы.

Вот несколько решений:

  • Импортировать jquery в ES6: здесь.
  • В конфиге WebPack укажите плагин jquery: здесь.

Реагировать, Redux, React-vis

На этот раз я хотел использовать react-vis для визуализации диаграммы. Это библиотека визуализации, основанная на D3 и разработанная Uber. Подведем итоги и процитируем их документы:

Набор компонентов React для визуализации общих диаграмм визуализации данных, таких как линейные / площадные / гистограммы, тепловые карты, диаграммы рассеяния, контурные графики, круговые и кольцевые диаграммы, солнечные лучи, радарные диаграммы, параллельные координаты и древовидные карты. / em>

Некоторые примечательные особенности:

  • Простота. react-vis не требует каких-либо глубоких знаний о библиотеках визуализации данных, прежде чем вы начнете создавать свои первые визуализации.
  • Гибкость. react-vis предоставляет набор основных строительных блоков для различных диаграмм. Например, он имеет отдельные компоненты осей X и Y. Это обеспечивает высокий уровень управления макетом диаграммы для приложений, которым это необходимо.
  • Простота использования. Библиотека предоставляет набор значений по умолчанию, которые могут быть отменены пользовательскими настройками.
  • Интеграция с React. react-vis поддерживает жизненный цикл React и не создает ненужных узлов.

Вот некоторые практические вопросы, с которыми я столкнулся и решил:

  • Сделайте диаграмму response-vis адаптивной, например this
  • Чтобы правильно использовать градиенты в react-vis, убедитесь, что вы включили их в график и настроили контрольные точки. Проверь это.
  • Используйте LineSeries вместо LineMarkSeries для повышения производительности (см. Ту же ссылку)

К этому моменту приложение было уже довольно неплохим. Теперь мне нужно было проверить последнюю User Story, которая отображает реальные изменения с использованием серверной части «веб-сокета».

Бэк-энд

Для данных я использовал открытый API от Quandl.

Сервер: index.js:

Настройка базы данных (MongoDB, размещенная на mLab)

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

const mongoose = require('mongoose');
var Schema = mongoose.Schema;
var stockSchema = new Schema({
  stockName: String
});
module.exports = mongoose.model('stockModel', stockSchema);

Затем подключите экспресс-сервер к mLab.

Чтобы устранить предупреждение об устаревшем открытом соединении mongoose, используйте openURI.

Подробнее см. Здесь.

Маршруты

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

Добавление Websocket

Используйте документацию Socket, чтобы настроить слушателей для:

  • Показать соединение
  • Показать отключение
  • Сохранять данные в базе
  • Удалить данные из базы данных

Не забудьте интегрировать функцию слушателя с моделью мангуста, чтобы использовать всю мощь MongoDB.

Кстати, потому что я потратил буквально одну неделю на эту проблему:

Используйте socket.BROADCAST.emit для отправки сообщения ВСЕМ сокетам!

Подробнее см. Здесь.

Адаптируйте интерфейс к WebSocket

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

Для этих конфигураций ключом к решению проблемы как в самом компоненте, так и в утках (файлах Redux).

Я решил это, подключив компонент-контейнер к клиенту socket.io и прислушиваясь к изменениям. Я сделал это с жизненным циклом componentDidMount. Каждый раз, когда сокет отправляет сообщение, компонент обращается к базе данных, отправляя действия файлам Redux.

В файлах Redux я получил данные из базы данных и сравнил их с текущим хранилищем приложения. В зависимости от этого сравнения приложение снова извлекает все данные из службы Quandl. Таким образом, каждый новый клиент сокета может проверить себя и всегда иметь самые свежие данные.

Обратите внимание: я не уверен, что это лучшая практика для приложения Redux / React, поскольку я обрабатываю большую часть логики в асинхронном действии. Не стесняйтесь указывать на ошибки или неверно понятые концепции! :)

Асинхронные действия в ducks / stocks.js (фрагмент):

// Async actions with thunk
export function checkDB(stocks) {
	return dispatch =>
		axios
			.get('/api/stocks')
			.then(res => {
				if (stocks.length === 0) {
					res.data.map(elem => {
						dispatch(fetchStock(elem.stockName));
					});
				} else if (res.data.length < stocks.length) {
					dispatch(removeStock(stocks.length - 1));
				} else {
					let diff = [];
					res.data.map((item, i) => {
						if (i < stocks.length) {
							if (res.data[i].stockName !== stocks[i].dataset.dataset_code) {
								diff.push({
									stockName: item.stockName
								});
							}
						} else if (i === stocks.length) {
							diff.push({
								stockName: item.stockName
							});
						} else {
							diff = [];
						}
					});
					diff.map(elem => {
						dispatch(fetchStock(elem.stockName));
					});
					diff = [];
					// console.log(res);
				}
			})
			.catch(err => {
				console.warn(err);
			});
}
export function fetchStock(stockCode) {
	return dispatch =>
		axios
			.get(
				`https://www.quandl.com/api/v3/datasets/WIKI/${stockCode}.json?api_key=${process
					.env.REACT_APP_QUANDL_KEY}`
			)
			.then(res => {
				dispatch(addStock(res.data));
				// console.log(res.data);
			})
			.catch(err => {
				console.error(err);
				toastr['warning'](' ', 'Stock Code cannot be found!');
			});
}
export function newStock(stockCode, socket) {
	socket.emit('update', stockCode);
	return dispatch =>
		axios
			.get(
				`https://www.quandl.com/api/v3/datasets/WIKI/${stockCode}.json?api_key=${process
					.env.REACT_APP_QUANDL_KEY}`
			)
			.then(res => {
				dispatch(addStock(res.data));
				// console.log(res.data);
			})
			.then(socket.emit('addStock', stockCode))
			.catch(err => {
				console.error(err);
				toastr['warning'](' ', 'Stock Code cannot be found!');
			});
}
export function deleteStock(ind, stockCode) {
	const socket = socketIOClient('https://createdd-stockmarketchart.herokuapp.com/');
	socket.emit('removeStock', stockCode);
	return dispatch => {
		dispatch(removeStock(ind));
		console.log(`Deleted ${stockCode}`);
	};
}

Складной контейнер - CollapsibleCon.js

Развернуть на Heroku

Для развертывания в Heroku важно:

  • использовать buildpack create-response-app при использовании сервера webpack
  • использовать buildpack nodeJs при использовании собственного веб-сокета с экспресс-сервером
  • установить переменные среды

Посмотреть результат

  • См. живое приложение здесь.
  • См. открытый исходный код здесь.
  • См. 5-минутный таймлап здесь.
  • См. 1-часовой сеанс расслабляющего программирования здесь.

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