Перейти к основному содержимому

Действия

Неофициальный Бета-перевод

Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →

Redux FAQ: Действия

Почему type должен быть строкой? Зачем использовать константы для типов действий?

Как и в случае с состоянием, сериализуемые действия обеспечивают ключевые возможности Redux, такие как отладка с путешествием во времени, запись и воспроизведение действий. Использование Symbol для значения type или проверка действий через instanceof нарушили бы эту функциональность. Строки сериализуемы и легко интерпретируемы, поэтому они являются предпочтительным выбором. Примечание: допустимо использовать Symbols, Promises или другие несериализуемые значения в действиях, если они предназначены для middleware. Действия должны стать сериализуемыми только к моменту их попадания в хранилище и передачи редьюсерам.

Из соображений производительности мы не можем гарантировать сериализуемость действий, поэтому Redux проверяет лишь, что каждое действие — простой объект, а type является строкой. Остальное зависит от вас, но поддержание сериализуемости помогает в отладке и воспроизведении проблем.

Инкапсуляция и централизация часто используемого кода — фундаментальный принцип программирования. Хотя можно вручную создавать объекты действий везде и прописывать каждый type отдельно, определение переиспользуемых констант упрощает поддержку кода. Разместив константы в отдельном файле, вы сможете проверять опечатки в import, что исключит случайное использование неправильной строки.

Дополнительные материалы

Документация

Обсуждения

Всегда ли есть взаимно однозначное соответствие между редьюсерами и действиями?

Нет. Мы рекомендуем создавать небольшие независимые функции-редьюсеры, каждая из которых отвечает за обновление определённой части состояния. Этот паттерн называется «композиция редьюсеров». Одно действие может обрабатываться всеми, несколькими или ни одним из них. Это разделяет компоненты и изменения данных, поскольку одно действие может затрагивать разные части дерева состояния без ведома компонентов. Некоторые пользователи предпочитают более тесную связь, как в структуре «ducks», но изначально соответствие не является взаимно однозначным, и стоит отойти от этой парадигмы, если требуется обрабатывать действие в нескольких редьюсерах.

Дополнительные материалы

Документация

Обсуждения

Как представить «побочные эффекты», такие как AJAX-запросы? Почему нам нужны сущности вроде «action creators», «thunks» и «middleware» для асинхронного поведения?

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

Любое значимое веб-приложение должно выполнять сложную логику, обычно включающую асинхронную работу, такую как выполнение AJAX-запросов. Такой код больше не является чистой функцией своих входных данных, а взаимодействия с внешним миром известны как «побочные эффекты».

Redux вдохновлён функциональным программированием и изначально не предоставляет места для выполнения побочных эффектов. В частности, функции редьюсеров должны всегда оставаться чистыми функциями вида (state, action) => newState. Однако middleware Redux позволяет перехватывать отправленные действия и добавлять дополнительное сложное поведение, включая побочные эффекты.

В целом Redux предлагает размещать код с побочными эффектами в процессе создания действий. Хотя эту логику можно выполнять внутри UI-компонента, обычно разумнее вынести её в переиспользуемую функцию, чтобы ту же логику можно было вызывать из нескольких мест — другими словами, в функцию-создатель действия.

Самый простой и распространённый способ — добавить middleware Redux Thunk, который позволяет писать создатели действий со сложной асинхронной логикой. Другой популярный метод — Redux Saga, позволяющий писать код, похожий на синхронный, с использованием генераторов, который может работать как «фоновые потоки» или «демоны» в Redux-приложении. Ещё один подход — Redux Loop, который инвертирует процесс, позволяя редьюсерам объявлять побочные эффекты в ответ на изменения состояния и выполнять их отдельно. Помимо этого, существует множество других библиотек и идей, разработанных сообществом, каждая со своим взглядом на управление побочными эффектами.

Дополнительные материалы

Документация

Статьи

Обсуждения

Какой асинхронный middleware выбрать? Как определиться между thunks, sagas, observables или другими решениями?

Существует множество middleware для асинхронных операций и побочных эффектов, но чаще всего используются redux-thunk, redux-saga и redux-observable. Это разные инструменты с уникальными сильными сторонами, ограничениями и сценариями применения.

Общие рекомендации:

  • Thunks лучше всего подходят для сложной синхронной логики (особенно когда нужен доступ ко всему состоянию Redux) и простых асинхронных операций (например, базовых AJAX-запросов). С использованием async/await они также могут применяться для более сложной promise-логики.

  • Sagas оптимальны для сложной асинхронной логики и разделения фоновых операций, особенно если нужно реагировать на отправленные действия (что невозможно с thunks). Требуют знания генераторов и операторов "effects" из redux-saga.

  • Observables решают те же задачи, что и саги, но используют RxJS для асинхронного поведения. Требуют знакомства с API RxJS.

Большинству пользователей Redux мы рекомендуем начинать с thunks, а затем добавлять sagas или observables только при реальной необходимости в обработке сложной асинхронной логики.

Поскольку саги и observables решают схожие задачи, приложение обычно использует что-то одно. Однако можно комбинировать thunks с сагами или observables, так как они решают разные проблемы.

Статьи

Обсуждения

Допустимо ли диспатчить несколько экшенов подряд из одного action creator?

Нет строгих правил структурирования экшенов. Асинхронные middleware типа Redux Thunk позволяют диспатчить несколько связанных экшенов последовательно, отражать прогресс AJAX-запроса, условно диспатчить экшены на основе состояния или даже проверить обновлённое состояние сразу после диспатча.

Оцените, являются ли экшены независимыми или должны быть объединены. Найдите баланс между читаемостью редюсеров и лога действий. Например, один экшен со всем состоянием сделает редюсер однострочным, но затруднит отладку, так как теряется история изменений. Если вы диспатчите экшены в цикле для детализации — возможно, стоит ввести новый тип экшена с особой обработкой.

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

Дополнительные материалы

Документация

Статьи

Обсуждения