Мы подходим к одному из основных моментов в изучении Redux. Если до этого мы вручную собирали наш магазин состояния, писали редьюсеры и настраивали слайсы, то сегодня мы наденем шляпу детектива. Мы вооружимся инструментом, который превратит поиск и устранение ошибок из рутины в настоящее удовольствие. Это инструмент, который покажет вам всё, что происходит внутри вашего приложения, вплоть до каждого маленького изменения состояния. Знакомьтесь с Redux DevTools Extension.
Этот урок станет переломным моментом в вашем понимании того, как можно эффективно работать со сложным состоянием. Мы не просто будем смотреть на логи в консоли, мы будем буквально «путешествовать во времени» по состоянию нашего приложения.
Как установить Redux DevTools?
Redux DevTools это расширение для браузеров (Chrome, Firefox, Edge), которое подключается к вашему Redux-стору и предоставляет мощный интерфейс для его отладки. Оно позволяет вам в реальном времени видеть все отправки actions, следить за тем, как они изменяют состояние и «отматывать» эти изменения назад и вперед.
Одна из ключевых причин, почему Redux остается таким популярным, несмотря на появление более простых альтернатив, это его предсказуемость и невероятные возможности для отладки, которые предоставляет это расширение.
Установка происходит в два простых шага:
-
Установите расширение из магазина вашего браузера. Просто зайдите в Chrome Web Store, Firefox Add-ons или Microsoft Edge Add-ons и найдите «Redux DevTools». Установите его, как любое другое расширение.
-
Настройте ваш Store. И вот здесь проявляется вся суть Redux Toolkit (RTK). Помните функцию
configureStore? Она уже по умолчанию настраивает интеграцию с DevTools! Вам не нужно делать абсолютно ничего. Если расширение установлено, а ваш стор создан черезconfigureStore, DevTools автоматически его «увидит».
Давайте взглянем на наш стандартный код создания стора:
// store.js import { configureStore } from '@reduxjs/toolkit' import counterReducer from '../features/counter/counterSlice' export const store = configureStore({ reducer: { counter: counterReducer, // ... другие редьюсеры }, })
Этого кода достаточно. Когда вы откроете инструменты разработчика в браузере (F12), у вас появится новая вкладка «Redux». Открыв ее, вы попадете в командный центр управления состоянием вашего приложения.
Практическая задача 1: Убедитесь, что расширение установлено и работает. Создайте простое React-приложение с одним слайсом (например счетчиком), как мы делали в предыдущих уроках. Запустите приложение, откройте DevTools (вкладку Redux) и понажимайте на кнопки + и -. Вы должны видеть, как в интерфейсе DevTools появляются записи о отправке actions.
Обзор панели управления
Когда вы впервые откроете вкладку Redux, вы можете немного растеряться от количества кнопок и информации. Давайте разберем самые важные из них.
Слева вы видите список всех действий (actions), которые были отправлены (dispatched) в вашем приложении с момента его загрузки. Каждое действие показано со своим типом (например counter/increment) и payload (полезной нагрузкой), если она была.
Справа находится инспектор состояния (State). По умолчанию открыта вкладка «State», которая показывает текущее, «финальное» состояние всего вашего приложения в виде дерева. Вы можете разворачивать и сворачивать ветки, чтобы посмотреть, что хранится внутри counter, todos или любого другого слайса.
Но это лишь верхушка айсберга. Обратите внимание на другие вкладки:
-
Diff. Показывает только те части состояния, которые изменились после выбранного действия. Это невероятно полезно, когда у вас очень большое состояние и вам нужно быстро найти, что именно поменялось.
-
Action. Показывает полную информацию о выбранном действии. Его тип, payload и метаданные.
-
Trace. Может показывать стек вызовов для асинхронных действий, помогая понять, откуда именно пришел вызов.
Самая нужная панель управления находится внизу. Это ваша «панель видеомонтажа» для состояния приложения.
// Пример действия, которое вы увидите в списке { type: "counter/increment", payload: undefined, // DevTools также добавит свои метаданные, например, timestamp }
Практическая задача 2: Модифицируйте ваш слайс счетчика, чтобы он принимал payload. Например, добавьте экшен incrementByAmount, который увеличивает счетчик на переданное число. Диспатчте его с разными значениями (dispatch(incrementByAmount(5))) и наблюдайте в DevTools, как меняется payload в списке действий и состояние на вкладке State.
Путешествие по времени для состояний (Time-Travel Debugging)
А теперь приготовьтесь к самому крутому, к Time-Travel Debugging. Это не просто модное словосочетание, это функциональность, которая кардинально меняет подход к отладке.
Посмотрите на нижнюю панель DevTools. Вы увидите кнопки, очень похожие на элементы управления видеоплеером:
-
«Прыгнуть» (Jump). Кнопки со стрелками. Позволяют пошагово перемещаться по истории действий.
-
«Воспроизвести» (Play). Автоматически «проигрывает» всю историю изменений состояния.
-
«Перемотать» (Skip). Позволяет пропустить определенное действие, эффективно удаляя его из истории и пересчитывая состояние заново.
Как это работает на практике? Допустим, у вас есть цепочка действий: increment -> decrement -> incrementByAmount(10). Ваш счетчик прошел значения 1, 0, 10.
-
Вы можете нажать на действие
decrementв списке слева. -
Состояние справа мгновенно «отмотается» к тому моменту, когда счетчик был равен
0. -
При этом в вашем реальном интерфейсе (в браузере) состояние также изменится! Вы будете видеть значение
0. -
Теперь вы можете «запустить» историю с этого момента заново, но с другим действием. Например, вы можете нажать кнопку
incrementByAmount(20)в вашем приложении и история продолжится уже с новым действием.
Это дает вам возможность воспроизводить баги снова и снова, меняя условия. Вы можете найти момент, когда состояние стало неверным и проанализировать, какое действие и с какими данными привело к ошибке.
Практическая задача 3: В вашем приложении со счетчиком совершите 5 разных действий (увеличьте, уменьшите, добавьте кастомное число). Затем используйте кнопки «Jump» на нижней панели, чтобы перемещаться по ним. Обратите внимание, как меняется число в вашем интерфейсе на экране. Вы буквально управляете временем для состояния вашего приложения.
Инспектирование состояния и поиск узких мест
DevTools это не только отладка логики, но и анализ производительности. Давайте поговорим о вкладке «Inspector».
Переключившись на нее, вы получаете более продвинутый вид на ваши действия и состояние. Вы можете выделять определенные действия, видеть, сколько времени заняло их выполнение (что критично для асинхронных операций) и даже профилировать производительность.
Как проводить нагрузочное тестирование?
Допустим, вы хотите понять, насколько быстро ваше приложение обрабатывает большое количество синхронных действий (например добавление сотни задач в список).
-
В коде вашего компонента создайте кнопку, которая диспатчит 1000 экшенов
incrementв цикле.// Где-то в компоненте const dispatch = useDispatch(); const handleMassUpdate = () => { for (let i = 0; i < 1000; i++) { dispatch(increment()); } }; return <button onClick={handleMassUpdate}>Добавить 1000 раз!</button>;
-
Нажмите на эту кнопку.
-
В DevTools на вкладке «Inspector» вы увидите, как быстро (или медленно) обрабатывается эта пачка действий. Если есть серьезные «тормоза», это повод задуматься об оптимизации селекторов с помощью
createSelector(о чем мы говорили в Уроке 8) или о реструктуризации состояния.
Этот метод помогает находить «узкие места» в вашей Redux-логике до того, как пользователи столкнутся с проблемами.
Находим и исправляем баг с помощью только Redux DevTools
Давайте смоделируем реальную ситуацию. У нас есть простой слайс для управления списком задач, но в нем есть ошибка.
Шаг 1: Создаем «багнутый» слайс
// features/todos/todosSlice.js import { createSlice } from '@reduxjs/toolkit'; const initialState = { items: [], filter: 'all', }; const todosSlice = createSlice({ name: 'todos', initialState, reducers: { addTodo: (state, action) => { // ОШИБКА: Мы мутируем состояние напрямую, не используя Immer корректно? // На самом деле, RTK использует Immer, так что это легально. // Но давайте представим, что здесь другая ошибка. state.items.push({ text: action.payload, completed: false }); }, toggleTodo: (state, action) => { // БАГ НАХОДИТСЯ ЗДЕСЬ! const index = action.payload; // Ожидаем индекс // Но что, если мы передадим не индекс, а id объекта? // Или если индекс будет неверным? state.items[index].completed = !state.items[index].completed; }, setFilter: (state, action) => { state.filter = action.payload; }, }, }); export const { addTodo, toggleTodo, setFilter } = todosSlice.actions; export default todosSlice.reducer;
Шаг 2: Создаем простой компонент
// features/todos/TodoList.js import React, { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { addTodo, toggleTodo } from './todosSlice'; export const TodoList = () => { const dispatch = useDispatch(); const todos = useSelector((state) => state.todos.items); const [text, setText] = useState(''); const handleSubmit = (e) => { e.preventDefault(); if (text) { dispatch(addTodo(text)); setText(''); } }; // БАГ: Мы по ошибке передаем в toggleTodo текст задачи вместо ее индекса! const handleToggle = (todoText) => { // Это неправильно! toggleTodo ожидает индекс (number), а получает string. dispatch(toggleTodo(todoText)); }; return ( <div> <form onSubmit={handleSubmit}> <input value={text} onChange={(e) => setText(e.target.value)} /> <button type="submit">Добавить</button> </form> <ul> {todos.map((todo, index) => ( <li key={index} onClick={() => handleToggle(todo.text)} // Здесь ошибка! style={{ textDecoration: todo.completed ? 'line-through' : 'none' }} > {todo.text} </li> ))} </ul> </div> ); };
Шаг 3: Воспроизводим баг и используем DevTools
-
Запустите приложение.
-
Добавьте 2-3 задачи. Например: «Изучить Redux», «Написать код», «Найти баг».
-
Попробуйте нажать на любую задачу, чтобы переключить ее состояние. С большой вероятностью в консоли браузера вы увидите ошибку
Uncaught TypeError: Cannot read properties of undefinedи приложение может сломаться. -
Не перезагружайте страницу! Откройте Redux DevTools.
Шаг 4: Анализ в DevTools
-
В списке действий слева вы увидите последовательность
addTodoи последний экшенtoggleTodo. -
Кликните на последний
toggleTodo. На вкладкеActionвы увидите, что в качестве payload был передан текст задачи, например,"Написать код". Это явно не то, что ожидал редьюсер! -
Теперь посмотрите на вкладку
Stateв момент перед багнутым действием. Вы увидите массивitemsс вашими задачами. Понятно, чтоitems["Написать код"]этоundefined, отсюда и ошибка. -
Используйте Time-Travel. «Отмотайте» время назад, к моменту до вызова
toggleTodo. Ваш интерфейс восстановится.
Шаг 5: Исправление бага
Теперь, поняв причину, мы можем ее исправить. Мы должны передавать в toggleTodo не текст, а индекс задачи.
// Исправленный компонент TodoList.js // ... const handleToggle = (index) => { // Принимаем индекс dispatch(toggleTodo(index)); // Передаем индекс }; // ... <ul> {todos.map((todo, index) => ( <li key={index} onClick={() => handleToggle(index)} // Передаем индекс, а не текст style={{ textDecoration: todo.completed ? 'line-through' : 'none' }} > {todo.text} </li> ))} </ul> // ...
И одновременно стоит улучшить редьюсер, добавив проверку на случай, если индекс все же окажется невалидным.
// Улучшенный редьюсер в todosSlice.js toggleTodo: (state, action) => { const index = action.payload; // Защитная проверка if (index >= 0 && index < state.items.length) { state.items[index].completed = !state.items[index].completed; } },
Вот так, используя только Redux DevTools, мы не только нашли и поняли баг, но и смогли безопасно «откатиться» к рабочему состоянию приложения, чтобы спокойно исправить код.
Итоги 18-го урока
Redux DevTools окно в душу вашего приложения. Умение пользоваться им, это навык, который отличает новичка от опытного разработчика. Вы перестаете гадать, «почему тут значение 5?» и начинаете точно знать всю цепочку событий, которая к этому привела.
Вы научились:
-
Устанавливать и настраивать расширение.
-
Мониторить действия и состояние.
-
Использовать Time-Travel Debugging.
-
Проверять производительность.
-
Проводить полный цикл отладки реального бага.
Чем сложнее состояние, тем больше пользы вы извлечете из DevTools.
Чтобы не пропустить следующие материалы и закрепить знания на большом проекте, переходите к полному курсу на моем сайте. Полный курс с уроками по Redux и Redux Toolkit для начинающих ждет вас по ссылке
https://max-gabov.ru/redux-dlya-nachinaushih
Поддержка автора осуществляется с помощью специальной формы ниже, предоставленной сервисом «ЮMoney». Все платёжные операции выполняются на защищённой странице сервиса, что обеспечивает их корректность и полную безопасность.


