В настоящее время первое, что делают, когда они начинают разработку приложения React, - это использовать Redux (или API контекста React). В конце концов, нам нужно управлять состоянием нашего приложения.

К сожалению, Redux не лишен недостатков:

  • Настройка Redux долгая, особенно если вы просто хотите управлять своим состоянием для небольшого / среднего приложения.
  • Кривая обучения может быть крутой: когда вы начинаете работать с Redux, вы должны понимать такие концепции, как действия, редукторы, хранилища ...

То же самое и с Context API:

  • Всякий раз, когда значение контекста изменяется, все дерево компонентов в этом контексте повторно отображается, что не очень эффективно.

В этой статье мы представим Recoil как альтернативную библиотеку управления состоянием. Мы покажем, как установить Recoil и начать работу с ним, а также представим пример с использованием хуков и функций управления состоянием (атомов и селекторов). Код, использованный в статье, доступен по адресу https://github.com/La-Javaness/recoil-pokedex/tree/local-state-part-1.

Что такое отдача и зачем ее использовать?

Recoil - это библиотека государственного управления, разработанная Facebook и выпущенная на саммите React Europe 2020.

Основная цель Recoil - позволить вам управлять своим глобальным состоянием легко и эффективно.

Легко, потому что настройка Recoil сводится к заключению вашего приложения в оболочку с провайдером с именем <RecoilRoot />.

Эффективно, потому что, в отличие от React Context API, не каждый дочерний компонент будет повторно отображаться при изменении состояния Recoil.

На момент публикации статьи Recoil все еще находится в бета-версии (0.1.1). В этом выпуске все еще есть экспериментальная версия для React Native, и в нем еще нет инструментов разработчика для браузера (хотя они находятся в стадии разработки). До тех пор API для наблюдения, проверки и управления глобальными состояниями отдачи описан в этой части официальной документации по отдаче.

Концепции отдачи, используемые в этом руководстве

Для инициализации Recoil в приложении существует оболочка компонента с именем <RecoilRoot />. Это провайдер состояния всего вашего приложения. <RecoilRoot /> имеет необязательную опору initializeState для создания начального состояния.

Recoil основан на React Context API, но с улучшенной производительностью: только компоненты, которые подписались на состояние, будут повторно отрисованы, а не все дерево компонентов. Как и в случае с React Contexts, вы можете вложить несколько <RecoilRoot /> в свое приложение. Если вы это сделаете, самый внутренний корень будет полностью маскировать любые внешние корни, и только его состояние будет доступно его дочерним элементам.

Recoil предоставляет следующие концепции:

Атом

Атом - это объект, который представляет собой часть состояния. Атомы могут быть прочитаны и записаны из любого компонента. Компоненты, считывающие значение атома, неявно подписаны на этот атом, поэтому любые обновления атома приведут к их повторной визуализации. Конструктор атома принимает уникальную строку ключа и значение по умолчанию и возвращает объект JS.

Селектор

Селектор - это объект, который представляет собой часть производного состояния. Производное состояние - это преобразование состояния. Вы можете рассматривать производное состояние как результат передачи состояния чистой функции, которая каким-то образом его модифицирует. Селекторы могут быть синхронными или асинхронными. Конструктор селектора принимает уникальную строку ключа и get / set для получения значения из выбранного атома и обновления значения атома. Конструктор селектора возвращает объект JS, который можно рассматривать как эквивалент атома.

Поскольку концепции атома и селектора часто могут использоваться как взаимозаменяемые, в документации по отдаче упоминается состояние отдачи, означающее либо атом, либо селектор.

Крюки для отдачи

Хук useRecoilState неявно подписывает вызывающий его компонент на заданное состояние отдачи. Этот API похож на ловушку React useState(), за исключением того, что в качестве аргумента он принимает атом отдачи (или селектор) вместо значения по умолчанию. Хук возвращает как текущее значение, так и функцию установки.

useRecoilValue возвращает значение данного состояния отдачи. Эта ловушка также подписывает вызываемый компонент на обновления используемого состояния. Однако он возвращает только текущее значение атома без функции установки.

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

Основное использование

Прежде всего, вам необходимо установить Recoil.js.

yarn add recoil

Как только это будет сделано, вам просто нужно обернуть ваше приложение <RecoilRoot />.

Очень просто! Вот почему Recoil больше подходит, чем другие решения, такие как Redux, для малых / средних приложений.

Пример всего приложения - простой Pokedex

Приложение, которое мы создадим, будет иметь следующие функции:

  • Составьте список имеющихся у вас покемонов
  • Добавить покемона
  • Отфильтруйте своих покемонов по типу
  • Дайте статистику по вашей коллекции покемонов

Все ресурсы, используемые в этом примере, доступны на GitHub. Небольшое примечание о правилах написания: чтобы помочь распознать атомы и селекторы в нашем коде, каждый из них будет иметь суффикс Atom или Selector, например. атом, инициализирующий наш список покемонов, называется pokemonListAtom.

В Recoil все начинается с атома, поэтому он нам нужен для создания нашего списка покемонов. Как видите, эти покемоны французские ;-)

С помощью этого атома вы инициализировали часть состояния. Каждый компонент, использующий этот атом, подпишется на него. Если вы открыли ссылку GitHub, то заметили, что мы создали папку, предназначенную для управления состоянием нашего приложения, папку state, в которой находятся следующие файлы:

  • atom.js, содержащий все созданные нами атомы.
  • selectors.js, содержащий все селекторы.

Теперь мы можем создать базовый компонент, отображающий наш список покемонов. Чтобы получить значение нашего атома, этот компонент вызывает ловушку useRecoilValue.

Далее мы можем построить селектор. Представим, что мы хотим отфильтровать наш список покемонов. Мы создадим atom, который представляет текущий фильтр, который нужно применить, и selector, который применяет этот фильтр atom к pokemonListAtom atom для создания отфильтрованного списка покемонов. Мы добавим в наш файл state / atom.js следующее:

И следующее в наш файл state / selectors.js. Функция get позволяет вам читать и преобразовывать значение одного (или нескольких) атомов.

Что делать, если вам нужна дополнительная информация о вашем списке покемонов? Давайте извлечем статистику на основе того же atom и предоставим их в качестве нового селектора.

Теперь мы можем создать компонент Filter.js :

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

В приведенном ниже коде мы реализуем форму для добавления покемона. Форма использует обычное состояние React для хранения входных значений. Обратный вызов onSubmit добавляет текущее состояние покемона в список покемонов get и сбрасывает форму.

Форма никогда не перерисовывается из-за изменений в атоме, поскольку useSetRecoilState не подписывает вызывающий объект на обновления.

Благодаря всему вышеперечисленному, теперь вы можете добавить нового покемона в свой pokedex, отфильтровать его и произвести статистику по элементам покемонов.

Как масштабировать ваше приложение с помощью Recoil?

Если вы хотите использовать Recoil для большого приложения, вам, вероятно, потребуется получать данные из API. Инструменты, необходимые для этого, включены в Recoil, в том числе:

  • Асинхронные селекторы
  • Саспенс
  • selectorFamily
  • атомСемья
  • useRecoilCallback

Мы расширим наш pokedex, используя эти концепции во второй статье, поэтому не стесняйтесь нажимать кнопку Follow ниже, если вы не хотите ее пропустить! Вы также можете узнать больше о нас в Linkedin и Twitter и на нашем веб-сайте, посетите наш GitHub, посмотрите другие наши публикации на Medium.

Хочу поблагодарить Steve Dodier-Lazaro и Vincent Le Badezet за вычитку этой статьи.

О

Максим Конан - ведущий фронтенд-разработчик в La Javaness с 2019 года.