Сообщение изначально опубликовано в Блоге LogRocket

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

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

Местное состояние

Локальное состояние в React позволяет вам создавать простой объект javascript для компонента и хранить информацию, которая может повлиять на его рендеринг. Локальное состояние управляется изолированно внутри компонента без влияния на него других компонентов.

Имейте в виду, что использование локального состояния в контексте React требует от вас создания компонентов с использованием классов ES6, которые поставляются с функцией конструктора для реализации начальных требований к компоненту. Кроме того, у вас есть возможность использовать хук useState при создании функциональных компонентов.

В компоненте, созданном с помощью классов ES6, всякий раз, когда изменяется состояние (доступно только через функцию setState), React запускает повторную визуализацию, которая необходима для обновления состояния приложения. Вот пример.

Представьте, что вышеуказанный компонент действует как цветочный магазин, у которого есть внутренняя система отслеживания, чтобы увидеть, сколько роз есть в магазине в данный момент времени. Это может работать правильно, если компонент FlowerShop является единственным объектом, который должен иметь доступ к этому состоянию. Но представьте, если этот магазин решит открыть второй филиал (возможно, в более красивом районе. В этом случае второму цветочному магазину также потребуется доступ к количеству доступных роз (он же this.state). Что-то, что невозможно с использование локального состояния.

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

Редукс Магазин

Итак, мы подошли ко второму варианту использования, который представляет собой общее состояние между компонентами. Здесь в игру вступает магазин редуксов. В двух словах, у redux есть глобальное хранилище, которое действует как источник правды для вашего приложения. Чтобы распространить это на пример с цветочным магазином, представьте себе главный офис цветочного магазина. Теперь эта штаб-квартира знает все о сетевых магазинах цветочных магазинов, и если кому-то из них понадобится доступ к имеющемуся количеству роз, она сможет предоставить им эту информацию. Вот пример.

Для целей нашего текущего обсуждения важными выводами из приведенной выше структуры Redux являются функции mapStateToProps и connect. В этом сценарии, когда запускается такое событие, как функция buyRose, событие отправляется и глобальное хранилище избыточности обновляется.

В результате мы используем функцию mapToState, чтобы получить доступ к глобальному хранилищу редукса и использовать его в качестве реквизита в компоненте FlowerShop. Самое замечательное в этой структуре то, что всякий раз, когда мы обновляем свойства, React запускает повторный рендеринг, точно так же, как обновление состояния.

Наконец, connect — это волшебная функция, которая склеивает все вместе, поэтому наши компоненты FlowerShop и их реквизиты будут сопоставлены с глобальным хранилищем и его состоянием.

Redux — это мощный инструмент с логическими концепциями, упрощающими понимание и управление структурой состояния приложения; особенно для приложения, которое больше по объему. Но это может создать много проблем для более простых и небольших приложений, которые могут не понадобиться. Кроме того, это не единственное решение для управления глобальным состоянием вашего приложения. Для вас, как разработчика или архитектора программного обеспечения, более важно понимать причины, лежащие в основе структуры Redux. В этом случае вы сможете использовать его более эффективно для своего приложения или даже создать собственное минималистическое решение, которое будет более эффективным. Мы рассмотрим это далее.

Погрузчики

Как представил Дэн Абрамов, существует два типа компонентов React: презентационные и контейнерные компоненты. Например, презентационные компоненты должны быть тупыми или не иметь состояния, в то время как контейнерные компоненты должны действовать как умные или с сохранением состояния. Но, как указано в статье, неверно предполагать, что какой-либо компонент принадлежит только к одной из этих категорий. Иногда совершенно нормально (и необходимо) игнорировать это различие, но принятие этой ментальной модели разделения сложной логики с отслеживанием состояния может окупиться в большой кодовой базе.

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

Представьте, что в вашем проекте есть объект определенного типа (например, список доступных цветов в нашем примере с цветочным магазином), который может понадобиться нескольким компонентам. В этом сценарии все родительские компоненты этих компонентов должны выполнить один и тот же вызов API и обновить свои индивидуальные состояния с помощью возвращенного результата API. Но мы не хотели повторяться и решили, что будет лучше извлечь функциональность и перенести ее в новые объекты, которые мы назвали lзагрузчиками.

Чтобы продолжить нашу работу с управлением состоянием компонентов, давайте создадим простой пример загрузчика. Загрузчик — это объект, который отвечает за выполнение вызова API за пределами презентационного компонента, а затем оборачивает этот компонент (отсюда компонент более высокого порядка) и сопоставляет его внутреннее состояние со реквизитами компонента. В этом случае компоненту не нужно ничего знать о том, как создаются его реквизиты. Просто и причудливо. Правильно! :)

Как вы можете видеть в приведенном выше примере кода, все процессы извлечения данных из вызова API и установки их в качестве свойств скрыты в загрузчике; поэтому, когда компонент, такой как FlowerShop, обертывается FlowerLoader, он имеет доступ к свойствам роз без необходимости хранить его в локальном состоянии или в состоянии резервного хранилища и обновлять его после каждого нового вызова API.

Вывод

Использовать локальное состояние, когда…

  • У вас очень простое приложение, и вы не хотите заморачиваться с настройкой такого инструмента, как redux.
  • Вам нужно использовать и устанавливать краткосрочные состояния, такие как введенное значение в текстовом вводе.
  • Состояние не нужно передавать другим компонентам

Использовать резервное хранилище, когда…

  • Ваше приложение более сложное, и необходимость разбивать состояние на разные разделы кажется необходимой.
  • Вам нужно использовать и устанавливать долгосрочные состояния, такие как результат вызова API.
  • Состояние должно быть передано другому компоненту

Используйте загрузчики, когда…

  • Вы повторяетесь, снова и снова устанавливая один и тот же тип состояния и средство обновления состояния. Использование загрузчика скроет это повторение.