git clone
cd client && npm install
cd server && npm install
cd stub && npm install
cd client && npm start
- ready app in dev modecd stub && npm start
- app stubcd server && npm start
- web server. generates random data
Directory client contains a fully implemented application. On the other hand, directory stub contains partially implemented application. You can improve your skill by implementing it by yourself.
If you have some problems with implementing you can check instruction below. I write down every step during the implementation.
Also in the implementation
branch you can find implemented stub
directory and commits for every part of instruction.
Before starting the implementation I recommend to see these diagrams...
I. Запустить счетчик температуры (сейчас статика)
- Смотрим
index.jsx
- В компонент Provider мы передаем общий state приложения
appStore
- Переходим в файл
app.store.js
из которого импортируетсяstore
- В компонент Provider мы передаем общий state приложения
- Смотрим
app.store.js
- В данном файле мы видим хинт (в виде комментария), который намекает нам, что нужно установить middleware для redux state.
- Для этого импортируем
createEpicMiddleware
функцию из библиотекиredux-observable
- Библиотека позволяет использовать epics в качестве middleware, поэтому нам необходимо подключить главный epic
rootEpic
- Делается это по аналогии с
rootReducer
- Создаём новый
epicsMiddleware
при помощиcreateEpicMiddleware
- Передаем
epicsMiddleware
вapplyMiddleware
- Сделали, получили ошибку
Module not found: Can't resolve './temperature/epics' in 'stub/src’
- Это ошибка означает, что у нас отсутсвует epic для компонента
temperature
- Создадим файл
epics.js
в директории./temperature
по аналогии с остальными директориями - Для начала импортируем вспомогательную функцию
FetchEpic
из файла../common/epic-creators.js
- Затем импортируем константы
FETCH
,FETCH_DONE
,FETCH_FAILED
из соответствующего данному компоненту редьюсера - Импортируем адаптер
- Затем экспортируем переменную
temperatureFetchEpic
, которая содержит в себе возвращаемый результат функцииFetchEpic
с переданными константами типов и функцией исполнения
- Это ошибка означает, что у нас отсутсвует epic для компонента
- Сделали, получили ошибку
Module not found: Can't resolve '../common/epic-creators'
- На самом деле сейчас у нас нет в проекте файла
epic-creators
, который содержит вспомогательную функциюFetchEpic
. - Добавим его… (тут можно и расписать подробнее :))
- На самом деле сейчас у нас нет в проекте файла
- Добавили, получили ошибку
'../conditions/reducer' does not contain an export named 'CALC_CONDITIONS'
- Просто добавим строчку
export const CALC_CONDITIONS = 'summary.calcConditions';
в качестве заглушки
- Просто добавим строчку
- Добавили, ошибок нет, но данные не обновляются.
- Идем в файл
app.reducer.js
и импортируемsyncReducer
- Затем добавляем его в
rootReducer
- Затем идем в
app.component.jsx
и импортируемSYNC_START
иAction
- При componentDidMount диспатчим
Action(SYNC_START)
- Идем в файл
- Сделали, получили ошибку в
conditions/epics.js
в функцииgetValueFromState
- Причина ошибки простая, функция опирается еще на не существующие записи в store precipitation, humidity и т.д.
- Необходимо просто исключить ненужные на данном этапе эпики из
rootEpic
- Закоментируем все строчки, кроме нужных нам
temperatureFetchEpic
,syncStartEpic
,syncEpic
- Заходим на страницу. Успех! Счетчик температуры обновляется!
- Коммит стэйбл вершион!
II. Запустить счетчик ветра (сейчас его нет)
- Добавим
windReducer
вapp.reducer.js
- Расскоментируем
windSpeedFetchEpic
,windDirectionFetchEpic
вapp.epics.js
- Откроем файл
app.component.jsx
и добавим компонентDashboardPanel
для отображения скорости ветра (по аналогии с температурой) - В таких props как
error
иloading
заменим'temperature'
на'wind'
this.getValue('temperature')
заменим наthis.getValue('wind.speed’)
. Так как ветер имеет как скорость так и направление- Осталось исправить функцию
getValue
, чтобы она могла принимать вложенные поля переменной... - Счетчик обновляется!
- Теперь добавим функцию
getWindDirectionIcon
для определения иконки ветра в зависимости от направления - И передадим соответствующую иконку в props компонента
DashboardPanel
- Иконка направления обновляется!
III. Запустить счетчик влажности (humidity)
- Добавим
humidityReducer
вapp.reducer.js
- Расскоментируем
humidityFetchEpic
вapp.epics.js
- Откроем файл
app.component.jsx
и добавим компонентDashboardPanel
для отображения влажности (по аналогии с температурой) - Заменим параметры
temperature
наwind
- Успех! Влажность обновляется!
- Коммит!
IV. Запустить учет conditions в верхнем компоненте на странице
- Идем в файл
conditions/reducer.js
- Видим, что в данный момент reducer всегда возвращает прежний
state
и начальное состояние равноsnow
- Устанавливаем начальное состояние равное
na
- Объявляем константу
CALC_CONDITIONS
- Пишем обработчик поступающих в Reducer событий (switch - case)
- Для события
CALC_CONDITIONS
напишем 2 вспомогательные функции:calcConditionsActionHandler
иcomposeConditions
calcConditionsActionHandler
вызывается при срабатывании событияCALC_CONDITIONS
и возвращает новыйstate
composeConditons
используется для расчета нового состояния на основе погодных данных
- Видим, что в данный момент reducer всегда возвращает прежний
- Далее идем в файл
app.epics.js
и добавляем эпикcalcConditionsEpic
- Так как для расчета состояния используется precipitation необходимо включить также соответсвующий epic и reducer
- Готово! Состояние обновляется!
- Коммит!
V. Подключить статистику
- Подключаем
statsReducer
вrootReducer
- Раскомментируем необходимые для статистики эпики в
rootEpic
- Открываем файл
app.component.jsx
- Создаем специальную функцию
getStatsFor(type)
которая возвращает статистику для определенного типа событий - Теперь нам необходимо передать props
statsValues
в каждый из компонентов
- Создаем специальную функцию
- Затем необходимо создать новый компонент
StatsTable
каждый и использовать его внутриdashboard-panel
компонента для отображения статистики - Сделали, получаем ошибку
«Cannot read property 'daily' of undefined»
. Это возникаем из-за того, что мы передали статистику только в 1 компонент (temperature), а остальные получают undefined. - Для решения в файле
stats-table.component.jsx
в методеgetValue
изначально проверяем values на undefined и возвращаем'--'
если это так. - Отлично! Статистика для температуры считается.
- Подключим остальные компоненты (ветер и влажность)
- Ура! Все компоненты ведут статистику!
- Коммит!
VI. При обновлении статистики было замечено, что не считается общая средняя температура
- Анализируем функцию
TotalStatsEpic
- Замечаем, что функцию считается с ошибкой для temperature, потому что в состоянии temperature отсутсвует
tick
- Анализируем редьюсер для temperature и понимаем, что он использует вложенные редьюсеры которые находятся в этом же файле.
- Заменяем их на аналогичные общие функции, которые успешно используются в остальных компонентах.
- Общая статистика работает!
- Коммит!