Spec-Zone.ru › Redux 3

Redux FAQ: React Redux

Содержание

  • Почему мой компонент не перерисовывается или не работает mapStateToProps?
  • Почему мой компонент перерисовывается слишком часто?
  • Как ускорить mapStateToProps?
  • Почему в моем подключенном компоненте недоступен this.props.dispatch?
  • Должен ли я подключать только верхний компонент или я могу подключить несколько компонентов в дереве?

React Redux

Почему мой компонент не перерисовывается или не работает mapStateToProps?

Самая распространенная причина, по которой компоненты не перерисовываются после отправки действия, заключается в непреднамеренном изменении или модификации состояния напрямую. Redux ожидает, что ваши редукторы будут обновлять состояние «неизменяемым» способом, что фактически означает всегда создание копий данных и применение изменений к этим копиям. Если вы возвращаете тот же объект из редуктора, Redux предполагает, что ничего не изменилось, даже если вы внесли изменения в его содержимое. Аналогично, React Redux пытается повысить производительность, выполняя проверки ссылок на поверхностное равенство для поступающих свойств в shouldComponentUpdate, и если все ссылки одинаковы, возвращает false для пропуска фактического обновления исходного компонента.

Важно помнить, что при обновлении вложенного значения необходимо также возвращать новые копии всех элементов выше него в дереве состояния. Если у вас есть state.a.b.c.d, и вы хотите внести обновление в d, вам также потребуется возвращать новые копии c, b, a, и state. Эта диаграмма мутации дерева состояния демонстрирует, как изменение глубоко в дереве требует изменений на всех уровнях.

Обратите внимание, что «обновление данных неизменяемым способом» не означает, что вы должны использовать Immutable.js, хотя это определенно вариант. Вы можете выполнять неизменяемые обновления обычных JS-объектов и массивов, используя несколько различных подходов:

  • Копирование объектов с помощью функций, таких как Object.assign() или _.extend(), и функций массивов, таких как slice() и concat().
  • Оператор spread для массивов в ES6 и аналогичный оператор spread для объектов, предложенный для будущих версий JavaScript
  • Библиотеки утилит, которые оборачивают логику неизменяемого обновления в более простые функции

Дополнительная информация

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

  • Устранение неполадок
  • React Redux: Устранение неполадок
  • Рецепты: Использование оператора spread для объектов
  • Рецепты: Структурирование редукторов - Предварительные понятия
  • Рецепты: Структурирование редукторов - Шаблоны неизменяемых обновлений

Статьи

  • Преимущества и недостатки использования неизменяемости с React
  • React/Redux Ссылки: Неизменяемые данные

Обсуждения

  • #1262: Неизменяемые данные + плохая производительность
  • React Redux #235: Функция-предикат для обновления компонента
  • React Redux #291: Должен ли mapStateToProps вызываться каждый раз, когда отправляется действие?
  • Stack Overflow: Более чистый и короткий способ обновления вложенного состояния в Redux
  • Gist: изменения состояния

Почему мой компонент перерисовывается слишком часто?

React Redux реализует несколько оптимизаций, чтобы гарантировать, что ваш компонент перерисовывается только при необходимости. Одной из них является проверка поверхностного равенства объединенного объекта свойств, генерируемого аргументами mapStateToProps и mapDispatchToProps, переданными connect. К сожалению, поверхностное равенство не помогает в тех случаях, когда новые экземпляры массивов или объектов создаются каждый раз, когда вызывается mapStateToProps. Типичным примером может быть отображение по массиву идентификаторов и возвращение соответствующих ссылок на объекты, таких как:

const mapStateToProps = state => {
  return {
    objects: state.objectIds.map(id => state.objects[id])
  }
}

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

Дополнительные перерисовки можно устранить, сохранив массив объектов в состоянии с помощью редуктора, кэшируя отображенный массив с помощью Reselect или реализовав shouldComponentUpdate в компоненте вручную и выполнив более глубокое сравнение свойств с помощью функции, такой как _.isEqual. Следите, чтобы ваше пользовательское shouldComponentUpdate() не было сложнее, чем само перерисовывание! Всегда используйте профайлер для проверки своих предположений о производительности.

Для компонентов, не подключенных к Redux, вы можете проверить передаваемые свойства. Распространенная проблема заключается в том, что родительский компонент перепривязывает обратный вызов внутри функции render, например, <Child onClick={this.handleClick.bind(this)} />. Это создает новую ссылку на функцию каждый раз, когда родительский компонент перерисовывается. Обычно рекомендуется привязывать обратные вызовы только один раз в конструкторе родительского компонента.

Дополнительная информация

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

  • FAQ: Производительность - Масштабирование

Статьи

  • Глубокое погружение в отладку производительности React
  • React.js anti-pattern производительности pure render
  • Повышение производительности React и Redux с помощью Reselect
  • Инкапсуляция дерева состояния Redux
  • React/Redux Ссылки: Производительность React/Redux

Обсуждения

  • Stack Overflow: Может ли приложение React Redux масштабироваться так же хорошо, как Backbone?

Библиотеки

  • Каталог дополнений Redux: DevTools - Мониторинг обновлений компонента

Как ускорить mapStateToProps?

Хотя React Redux работает над минимизацией количества вызовов вашей функции mapStateToProps, всё же имеет смысл обеспечить быстрое выполнение функции mapStateToProps и минимизировать объём выполняемой работы. Рекомендуемый подход заключается в создании кешированных «функций-селекторов» с помощью Reselect. Эти селекторы могут быть объединены и составлены, и селекторы, расположенные ниже по цепочке, будут выполняться только в том случае, если их входные данные изменились. Это означает, что вы можете создавать селекторы, выполняющие фильтрацию или сортировку, и гарантировать, что реальная работа происходит только при необходимости.

Дополнительная информация

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

  • Рецепты: Вычисление производных данных

Статьи

  • Повышение производительности React и Redux с помощью Reselect

Обсуждения

  • #815: Работа с структурами данных
  • Reselect #47: Кэширование иерархических селекторов

Почему в моем подключенном компоненте недоступен this.props.dispatch?

Функция connect() принимает два основных аргумента, оба необязательны. Первый, mapStateToProps, - это функция, которую вы предоставляете для извлечения данных из хранилища при их изменении и передачи этих значений в качестве свойств вашему компоненту. Второй, mapDispatchToProps, - это функция, которую вы предоставляете для использования функции dispatch хранилища, обычно для создания предварительно привязанных версий создателей действий, которые будут автоматически отправлять свои действия сразу после вызова.

Если вы не предоставляете собственную функцию mapDispatchToProps при вызове connect(), React Redux предоставит версию по умолчанию, которая просто вернёт функцию dispatch как свойство. Это означает, что если вы предоставите собственную функцию, dispatch не будет автоматически предоставлена. Если вы всё ещё хотите иметь её в качестве свойства, вам нужно явно вернуть её в своей реализации mapDispatchToProps.

Дополнительная информация

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

  • React Redux API: connect()

Обсуждения

  • React Redux #89: можно ли обернуть несколько actionCreators в одно свойство с именем?
  • React Redux #145: рассмотреть передачу dispatch всегда независимо от того, что делает mapDispatchToProps
  • React Redux #255: this.props.dispatch является неопределённым при использовании mapDispatchToProps
  • Stack Overflow: Как получить простой dispatch от this.props с использованием connect с Redux?

Должен ли я подключать только верхний компонент, или я могу подключить несколько компонентов в дереве?

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

Текущая рекомендуемая лучшая практика — категоризировать ваши компоненты как «представления» или «контейнеры» и извлекать соединенный компонент-контейнер, где это имеет смысл:

Подчёркивание «одного компонента-контейнера наверху» в примерах Redux было ошибкой. Не принимайте это как максиму. Старайтесь держать ваши компоненты представления раздельно. Создавайте компоненты-контейнеры, соединяя их, когда это удобно. Всякий раз, когда вы чувствуете, что дублируете код в родительских компонентах для предоставления данных для одинаковых типов дочерних компонентов, пришло время извлечь контейнер. В общем, как только вы почувствуете, что родительский компонент знает слишком много о «личных» данных или действиях своих дочерних компонентов, пришло время извлечь контейнер.

На самом деле, тесты показали, что большее количество соединённых компонентов, как правило, приводит к лучшей производительности, чем меньшее количество соединённых компонентов.

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

Дополнительная информация

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

  • Основы: Использование с React
  • ЧАВО: Производительность — Масштабирование

Статьи

  • Компоненты презентации и контейнеры
  • Высокая производительность Redux
  • React/Redux Ссылки: Архитектура — Архитектура Redux
  • React/Redux Ссылки: Производительность — Производительность Redux

Обсуждения

  • Твиттер: подчёркивание «одного контейнера» было ошибкой
  • #419: Рекомендуемое использование connect
  • #756: контейнер vs компонент?
  • #1176: Redux+React только с бессостоятельными компонентами
  • Stack Overflow: может ли бессостоятельный компонент использовать компонент-контейнер Redux?

© 2015–2017 Dan Abramov
Licensed under the MIT License.
http://redux.js.org/docs/faq/ReactRedux.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API