Как установить devtools redux
Всем привет. В этом уроке мы разберем, что такое redux-devtools. Это специальное расширение для браузера, которое позволяет легко дебажить redux приложения.
Для установки из Chrome Web Store, переходим по этой ссылке и установить его в свой хром.
Теперь нам нужно изменить наш createStore, чтобы он подключался с redux-devtools. Для этого вторым параметром в createStore передадим
То есть если у нас найдено расширение redux-devtools, мы применяем его как второй аргумент метода createStore. Теперь если мы откроем браузер, то мы видим вкладку Redux в которой мы можем дебажить наше приложение.
Давайте добавим трек Fade to black. Слева от store у нас отображаются наши екшены. И мы видим, что после того, как мы добавили трек у нас отобразился новый екшен ADD_TRACK. Екшен @@INIT, который мы видим до этого, всегда выстреливает, когда redux инициализируется.
Кликая по екшенам слева, мы видим, как меняется наш store справа. То есть мы можем по шагам каждого екшена дебажить как меняется наш store.
Также мы можем скипать екшены. Давайте добавим еще 1 трек Back in black. Если мы нажимаем skip, то екшен пропускается и мы видим, что ничего не ломается, а просто этот екшен не применяется к store.
На каждом екшене пишется время, которое прошло с момента последнего екшена. Это удобно, если екшены асинхронные и вы хотите узнать, сколько времени прошел запрос от start до success.
Также вы можете диспатчить екшены прямо из redux-devtools. Для этого кликаем Dispatcher и пишем там
Также вы можете посмотреть как написать тесты на какой-то екшен. Для этого нашимаем на какой-то екшен и выбираем вкладку test. Здесь показан маленький пример как протестировать наш екшен. Мы импортируем наш reducer и передаем ему начальные значения и екшен и тестируем какой будет стейт в конце.
С 0 до 1. Разбираемся с Redux
Когда вышла версия 1.0 Redux, я решил потратить немного времени на серию рассказов о моем опыте работы с ним. Недавно я должен был выбрать “реализацию Flux” для клиентского приложения и до сих пор с удовольствием работаю с Redux.
Почему Redux?
Redux позиционирует себя как предсказуемый контейнер состояния (state) для JavaScript приложений. Редакс вдохновлен Flux и Elm. Если вы раньше использовали Flux, я советую прочитать, что Redux имеет с ним общего в разделе «Предшественники» новой (отличной!) документации.
Redux предлагает думать о приложении, как о начальном состоянии модифицируемом последовательностью действий (actions), что я считаю действительно хорошим подходом для сложных веб-приложений, открывающим много возможностей.
Конечно, вы можете найти больше информации о Redux, его архитектуре и роли каждого компонента в документации.
Создаем список друзей с React и Redux
Сегодня мы сфокусируемся на пошаговом создании вашего первого приложения, использующего Редакс и Реакт: создадим простой список друзей с нуля.
Вы можете найти готовый код здесь.
Для кого?
Эта статья написана для людей, не имеющих опыта работы с Redux. Опыт разработки с Flux также не обязателен. Я буду давать ссылки на документы, когда мы будем сталкиваться с новыми понятиями.
1. Установка
Автор Redux, Даниил Абрамов, создал отличную сборку для разработки с React, Webpack, ES6/7 и React Hot Loader, которую вы можете найти здесь.
Есть сборки уже с установленным Redux, но, я думаю, важно понять роль каждой библиотеки.
Теперь вы можете открыть приложение по адресу http://localhost:3000. Как вы видите, «hello world» готов!
1.1 Добавим redux, react-redux и redux-devtools
Нам нужно установить три пакета:
1.2 Структура директорий
Хотя то, что мы будем делать, довольно просто, давайте создадим структуру директорий как для реального приложения.
Мы будет видеть более детально роль каждой из директорий, когда будем создавать приложение. Мы переместили App.js в директорию containers, так что нужно будет настроить импорт statement в index.js.
1.3 Подключаем Redux
Нам нужно включить devtools только для окружения разработки, так что модифицируем webpack.config.js как здесь:
Мы делаем здесь две вещи. Мы переопределяем createStore используя созданную функцию, которая позволяет нам применять множественные store enhancers, таких как devTools. Мы также включаем функцию renderDevTools, которая рендерит DebugPanel.
Сейчас нам нужно модифицировать App.js для соединения с redux. Для этого мы будем использовать Provider из react-redux. Это сделает наш экземпляр хранилища доступным для всех компонентов, которые располагаются в Provider компоненте. Не нужно беспокоится о странно выглядящей функции, ее цель использовать “контекст” функции Реакта для создания хранилища, доступного для всех детей (компонентов).
Для создания хранилища мы используем createStore функцию, которую мы определили в devTools файле, как map всех наших редьюсеров.
В нашем приложении App.js — внешняя обертка для Redux и FriendListApp — корневой компонент для нашего приложения. После создания простого ‘Hello world’ в FriendListApp.js, мы можем наконец запустить наше приложение с redux и devTools. Вы должен получить это (без стилей).
Хотя это просто ‘Hello world’ приложение, у нас включен Hot Reloading, т.е. вы можете модифицировать текст и получать автоматическое обновление на экране. Как вы можете видеть, devtools справа показывает пустые хранилища. Заполним их!
2. Создаем приложение
Теперь, когда сделаны все настройки, мы можем сфокусироваться на самом приложении.
2.1 Действия и генераторы действий
Как вы можете видеть, это очень выразительный путь определения области действий нашего приложения, которое будет позволять нам добавлять друзей, отмечать их как «избранных» или удалять их из нашего списка.
Генераторы действий — функции, которые создают действия. В Redux генераторы действий являются чистыми функциями, что делает их портативными и простыми для тестирования, т.к. они не имеют сайд-эффектов.
Мы поместим их в папку действий, но не забывайте, что это разные понятия.
Как видите, действия довольно минималистичны. Чтобы добавить элемент, мы сообщаем все свойства (здесь мы имеем дело только с name), а для других мы ссылаемся на id. В более сложном приложении, мы, возможно, имели бы дело с асинхронными действиями, но это тема для другой статьи…
2.2 Редьюсеры
Мы, для начала, определяем вид состояния нашего приложения в initialState :
Состоянием может быть все, что мы захотим, мы можем просто сохранить массив друзей. Но это решение плохо масштабируется, так что мы будем использовать массив id и map друзей. Об этом можно почитать в normalizr.
Теперь нам нужно написать актуальный редьюсер. Мы воспользуемся возможностями ES6 для задания аргументов по умолчанию для обработки случаев, когда состояние не определено. Это поможет понять как записать редьюсер, в данном случае я использую switch.
Если вы не знакомы с синтаксисом ES6/7, то возможно вам будет трудно это прочесть. Т.к. нам нужно вернуть новое состояние объекта, как правило используют Object.assign или Spread operator.
Что здесь происходит: мы определяем новый id. В реальном приложении мы, возможно, возьмем его с сервера или, как минимум, убедимся, что он уникальный. Затем мы используем concat чтобы добавить этот новый id в наш id-лист. Concat добавит новый массив и не изменит оригинальный.
Как вы можете видеть, несмотря на синтаксис, который может сначала смутить, логика проста. Вы задаете состояние и получаете назад новое состояние. Важно: ни в одной точке этого процесса не изменять предыдущее состояние.
Окей, давайте вернемся и создадим редьюсеры для двух других действий:
Вы также можете заметить, что spread оператор позволяет нам манипулировать только теми состояниями, которое нам нужно изменить.
Redux не важно, как вы храните данные, так что можно использовать Immutable.js.
Теперь вы можете поиграть с хранилищем минуя интерфейс, путем вызова dispatch вручную в нашем App.js.
Вы увидите в devTools действия, с ними можно поиграть в реальном времени.
3. Создаем интерфейс
Т.к. этот урок не об этом, я пропустил создание React-компонентов и сфокусировался только на Redax. Мы имеем три простых компонента:
В Redux считается хорошей практикой делать по возможности большинство компонентов “глупыми”. Т.е. чем меньше компонентов связаны с Redux, тем лучше.
Здесь FriendListApp будет единственным “умным” компонентом.
Это часть нового синтаксиса ES7, называемая декоратор. Это удобный способ вызова функции высшего порядка. Будет эквивалентна connect(select)(FriendListApp); где select — функция, которая возвращает то, что мы здесь сделали.
То, что случится дальше — стандартный подход для React. Мы привяжем функции к onClick, onChange или onKeyDown свойствам, чтобы обработать действия пользователя.
Если вы заинтересовались, как это сделать, ты можете посмотреть весь код.
Сейчас вы можете почувствовать магию работы redux/react приложения. Как изображено на GIF, вы логгируете все действия.
Разрабатывать удобней, когда ты можешь производить какие-то действия, находить баги, возвращаться, исправлять их и повторять уже исправленную последовательность…
Основы Redux для начинающих
Что такое Redux?
Redux — это инструмент для управления состоянием приложения. Построен на принципах технологии Flux и функционального программирования. Создан компанией FaceBook, но вопреки распространенному мнению может использоваться не только в связке с React, но также и с другими фреймворками/библиотеками.
Flux — это тип архитектуры и набор паттернов проектирования веб-приложений. Подробнее на Wiki
Redux использует методологию flux. Она состоит из 4 понятий:
В React по умолчанию нет какого-то глобального state (состояния), которое было бы доступно во всем приложении. Вы можете только сохранять данные в рамках одного компонента. К примеру, у вас есть интернет магазин и в нем есть корзина с товарами. Если работать только со стейтом компонента Корзина, то вам эти данные будут недоступны в других компонентах. Также например, у вас есть иконка корзины в углу экрана, которая должна показывать количество товара, которые пользователь добавил туда. Так вот средствами чисто React, это будет сложно реализовать.
Вот именно поэтому есть такие библиотеки как Redux, для хранения всех данных приложения в одном месте и удобного их обновления.
Основные понятия Redux
Как я уже писал выше, основные понятия редакса — actions, dispatcher, store.
Store — это состояние веб-компонента, которое хранит в себе всю информацию (или ту которую вы решили сохранить в него). В дальнейшем стор будет доступен из любого компонента вашего приложения.
Action — действие, описывает что нужно сделать. Согласно принципам функционального программирования, мы не можем изменять объект напрямую, поэтому нам нужны экшены, чтобы передать их в диспатчер и «сказать», что нужно сделать.
Dispatcher — сообщает хранилищу о каком-то действии (action) и передает ему обновленную информацию.
Теперь когда мы разобрали основные понятия, давайте посмотрим как работает Redux:
Схема работы Redux
Компонент генерирует действие (action), диспатчер сообщает об этом хранилищу (store), хранилище изменяет состояние и данные передаются в компонент (View).
Есть еще одно понятие в Redux это reducer (редюсер). Редюсер — это чистая функция, которая принимает как аргумент хранилище и экшен. Основные правила редюсеров:
Более подробно про чистые функции можно прочитать тут.
Простой пример использования Redux
Теперь на простом практическом примере разберем как работать с Redux.
Мы сделаем простое приложение ToDo, которое даст возможность создавать свои таски с сохранением их в store. Это будет простое приложение для примера, основной упор сделан на работу с Redux.
Итак, есть 2 варианта, вы можете скачать стартовый проект и просто запустить установку, или пошагово пройти и создать проект со старта.
Установка и настройка проекта
Чтобы создать приложение заново, открываем командную строку или Git Bash
Далее заходим в папку проекта и устанавливаем Redux и пакет для Реакта — react-redux
Если вы скачали архив с уже готовым приложением, тогда его нужно распаковать, войти в папку с приложением и в командной строке/терминале запустить команду:
Теперь, чтобы запустить наш проект нужно воспользоваться следующей командой:
Проект будет собран и запущен, автоматически откроется вкладка в браузере
Результат выполнения команды npm run start
Для того, чтобы не верстать всё заново, мы используем Bootsrap. Давайте его установим.
Также подключим стили в файле src/index.js
Создание базовой структуры для хранилища
Теперь давайте сделаем базовую структуру для Redux. Создадим папку src/store, а в ней 4 файла
Сначала определим какие типы экшенов нам нужны в файле actionTypes.js. Можно типы и не определять, но в дальнейшем это даст нам возможность сократить время на дебагинг, если вдруг понадобится изменить имя экшена, они все находятся в одном месте, что тоже удобно. Если нам понадобится экшен в другом месте, нам достаточно будет импортировать его в другом модуле.
В нашем приложении, например, нам нужен будет экшен в 2 файлах: actions и reducer. Создадим файл actionTypes.js и в нем определим наши типы:
В файле store/actions.js мы опишем все экшены, которые нам потребуются для приложения:
Выше вы видите типичную структуру экшена: это функция, которая возвращает объект с двумя свойствами:
Теперь давайте рассмотрим функцию редюсер (store/reducer.js):
Тут мы импортируем наши типы экшенов, затем определяем переменную для того, чтобы задавать ID каждому новому таску.
Сам reducer принимает в качестве аргументов state (или равняется пустому массиву) и экшен. Далее мы проверяем тип екшена и в зависимости от этого производим определенные манипуляции со стейтом.
Давайте размеберем на примере экшена TASK_ADD. При добавлении нового таска, нам необходимо сделать копию текущего стейта и добавить к нему новый таск
Далее на основании этого редюсера нам нужно создать store с помощью функции createStore. Создадим файл store.js с таким содержимым:
* У меня также вторым параметром добавлена след. строка
Это для работы плагина для Chrome — Redux DevTools. Удобный плагин для дебагинга.
Теперь после создания store, мы можем использовать его в любом модуле нашего приложения.
Основные методы для работы со store
Redux в функциональных компонентах (хуки)
Наше приложение будет построено при помощи функциональных компонентов и хуков, поэтому мы немного рассмотрим какие хуки предоставляет нам Redux для работы в таких компонентах.
. В документации редакса говорится о том, что лучше этот хук не использовать часто, а лучше пользоваться useSelector()
Теперь давайте вернемся к нашему приложению. В index.js нам нужно обернуть наше приложение в компонент Provider и передать ему store через пропсы. Store мы создали в файле store/store.js
Следующим шагом давайте создадим папку, в которой будем хранить наши компоненты и назовем ее componetns. В ней создадим 3 файла:
Для начала импортируем хук useDispatch(), т.к. в этом компоненте мы будем диспатчить 2 экшена: выполнение таска (toggleTask) и удаление (removeTask). В компоненте у нас есть событие onChange — при клике на этот компонент мы будем диспатчить экшен для переключения состояния таска, ну а при клике кнопки удалить — диспатчим экшен для удаления таска из нашего стора.
Далее файл src/components/TaskList.js
Теперь последний компонент AddNewTask.js
Тут у нас будет 2 обработчика handleTaskTitleChange() и handleTaskSubmit(). Последний будет диспатчить экшен для создания нового таска. В идеале, тут бы еще добавить проверку на пустую строку и обрезать лишние пробелы, но у нас не об этом сейчас 🙂
Теперь остался заключительный шаг, изменить файл scr/App.js и добавить немного стилей
В итоге у нас получилась вот такое приложение
Итоговое приложение
Как установить devtools redux
If you don’t want to bother with installing Redux DevTools and integrating it into your project, consider using Redux DevTools Extension for Chrome and Firefox. It provides access to the most popular monitors, is easy to configure to filter actions, and doesn’t require installing any packages.
If you want to have full control over where DevTools are displayed, or are developing a custom monitor, you will probably want to integrate them manually. It’s more steps, but you will have full control over monitors and their configuration.
You’ll also likely want to install some monitors:
Create a DevTools Component
Note that you can use LogMonitor directly without wrapping it in DockMonitor if you’d like to display the DevTools UI somewhere right inside your application:
Use DevTools.instrument() Store Enhancer
It’s important that you should add DevTools.instrument() after applyMiddleware in your compose() function arguments. This is because applyMiddleware is potentially asynchronous, but DevTools.instrument() expects all actions to be plain objects rather than actions interpreted by asynchronous middleware such as redux-promise or redux-thunk. So make sure applyMiddleware() goes first in the compose() call, and DevTools.instrument() goes after it.
Exclude DevTools from Production Builds
Finally, to make sure we’re not pulling any DevTools-related code in the production builds, we will envify our code. You can use DefinePlugin with Webpack, or envify for Browserify.
With Webpack, you’ll need two config files, one for development and one for production. Here’s a snippet from an example production config:
Render in Your App.
Finally, include the DevTools component in your page.
A naïve way to do this would be to render it right in your index.js :
We recommend a different approach. Create a Root.js component that renders the root of your application (usually some component surrounded by a
). Then use the same trick with conditional require statements to have two versions of it, one for development, and one for production:
. Or Open Them in a New Window
Personal preferences vary, and whether to put the DevTools in a separate window, in a dock, or right inside you app’s user interface, is up to you. Make sure to check the documentation for the monitors you use and learn about the different props they support for customizing the appearance and the behavior.
—just like with any connected component. To adjust the monitors, you need to pass props to them inside DevTools.js itself inside the createDevTools() call when they are used.
Your reducers have to be pure and free of side effects to work correctly with DevTools. For example, even generating a random ID in reducer makes it impure and non-deterministic. Instead, do this in action creators.
Make sure to only apply DevTools.instrument() and render in development! In production, this will be terribly slow because actions just accumulate forever. As described above, you need to use conditional require s and use DefinePlugin (Webpack) or loose-envify (Browserify) together with Uglify to remove the dead code. Here is an example that adds Redux DevTools handling the production case correctly.
It is important that DevTools.instrument() store enhancer should be added to your middleware stack after applyMiddleware in the compose d functions, as applyMiddleware is potentially asynchronous. Otherwise, DevTools won’t see the raw actions emitted by asynchronous middleware such as redux-promise or redux-thunk.
Now that you see the DevTools, you might want to learn what those buttons mean and how to use them. This usually depends on the monitor. You can begin by exploring the LogMonitor and DockMonitor documentation, as they are the default monitors we suggest to use together. When you’re comfortable using them, you may want to create your own monitor for more exotic purposes, such as a chart or a diff monitor. Don’t forget to send a PR to feature your monitor at the front page!
Как установить devtools redux
Redux DevTools Extension
4. For other browsers and non-browser environment
For a basic Redux store simply add:
For TypeScript use redux-devtools-extension npm package, which contains all the definitions, or just use (window as any) (see Recipes for an example).
In case ESLint is configured to not allow using the underscore dangle, wrap it like so:
Note: Passing enhancer as last argument requires redux@>=3.1.0. For older versions apply it like here or here. Don’t mix the old Redux API with the new one.
You don’t need to npm install redux-devtools when using the extension (that’s a different lib).
1.2 Advanced store setup
If you setup your store with middleware and enhancers, change:
Note that when the extension is not installed, we’re using Redux compose here.
To specify extension’s options, use it like so:
1.3 Use redux-devtools-extension package from npm
To make things easier, there’s an npm package to install:
and to use like so:
In case you don’t include other enhancers and middlewares, just use devToolsEnhancer :
1.4 Using in production
It’s useful to include the extension in production as well. Usually you can use it for development.
If you want to restrict it there, use redux-devtools-extension/logOnlyInProduction :
or with middlewares and enhancers:
If you’re already checking process.env.NODE_ENV when creating the store, include redux-devtools-extension/logOnly for production environment.
1.5 For React Native, hybrid, desktop and server side Redux apps
For most platforms, include Remote Redux DevTools ‘s store enhancer, and from the extension’s context menu choose ‘Open Remote DevTools’ for remote monitoring.
See integrations and the blog post for more details on how to use the extension with any architecture.
Live demos to use the extension with:
Support us with a monthly donation and help us continue our activities. [Become a backer]
Become a sponsor and get your logo on our README on Github with a link to your site. [Become a sponsor]
If you like this, follow @mdiordiev on twitter.