Пошаговое руководство с реальным примером
Репо для этого материала можно найти по адресу https://github.com/spearmintjs/spearmint.
Возможно, вы уже слышали, что вы можете использовать хуки useReducer
и useContext
вместо Redux. Когда я захотел попробовать это на себе, мне было трудно найти ресурсы, которые использовали бы хуки и контекст для существенного приложения. В этом посте вы узнаете, как использовать хуки и контекст для сложного общего состояния на реальном примере.
Заявление об ограничении ответственности: этот пост предполагает промежуточное знание React и Redux.
В качестве примера мы будем использовать spearmint: инструмент с открытым исходным кодом, который поможет разработчикам легко создавать функциональные тесты React без написания кода. Он динамически преобразует вводимые пользователем данные в исполняемый тестовый код Jest с помощью селекторов запросов DOM, предоставляемых react-testing-library
.
Хотя в этом приложении есть несколько useReducer
и useContext
ловушек, я буду рассматривать редуктор testCase
и то, как его состояние распределялось между несколькими компонентами.
Прежде чем мы начнем углубляться, я дам общий обзор того, что делает редуктор testCase. Компонент testCase
- это панель, которую вы видите посередине, а редуктор testCase
хранит все состояние для введенных пользователем операторов рендеринга, действий и утверждений. Когда мы нажимаем кнопку экспорта на компоненте NavBar
, запускается компонент ExportFileModal
. Как только пользователь нажимает кнопку сохранения в модальном окне, мы useContext
получаем доступ к состоянию из testCase
редуктора, чтобы сгенерировать тестовый файл.
Шаг 1: константы действий, создатели действий, редуктор
Эта часть проста: вы пишете их точно так же, как если бы вы использовали библиотеку Redux. Я буду вставлять здесь только сокращенную версию с тремя действиями. Вы можете просмотреть полный код для testCaseActions.js
или testCaseReducer.js
, если хотите.
Единственное, что следует отметить, - это строка 4 файла testCaseReducer.js
, где мы createContext
для testCase
. Мы не хотим предоставлять ему значение по умолчанию, поэтому мы передаем null в качестве аргумента. Обратите внимание, что вам не нужно createContext
в файле редуктора и можно createContext
в компоненте, где вы используете Provider (в нашем случае App.jsx
). Поскольку у нас было несколько контекстов, наш App.jsx
становился беспорядочным и решил переместить вызовы createContext
в каждый соответствующий файл редуктора.
Давайте посмотрим, как передать состояние редуктора useReducer
и поставщик контекста в следующем сеансе.
Шаг 2: useReducer и поставщик контекста
Теперь, когда у нас есть наши testCaseReducer
, testCaseState
и TestCaseContext
, мы хотим предоставить его компонентам, которые в нем нуждаются - компонентам TestCase
и ExportFileModal
.
Если вы посмотрите на упрощенную версию дерева компонентов для spearmint ниже, TestCase
- дочерний компонент контейнера LeftPanel
, а ExportFileModal
- дочерний компонент контейнера NavBar
. Поскольку App является общим родительским компонентом для LeftPanel
и NavBar
, мы хотим вызвать useReducer
в App.
Вот код для App.jsx
. Опять же, нерелевантный код был удален, и если вы хотите увидеть полный код приложения, вы можете посетить GitHub.
useReducer
принимает два аргумента, первый - это редуктор, а второй - начальное состояние. При вызове он возвращает массив, первое значение которого является фактическим состоянием, а второе значение - методом обновления состояния, которое мы назначаем новым переменным с помощью деструктуризации массива.
Затем мы оборачиваем компоненты, которые хотим разделить состояние testCase
, с TestCaseContext.Provider
. Вы можете предоставить поставщику только одно значение. Чтобы избежать создания отдельных контекстов для testCase
и dispatchToTestCase
, мы помещаем их в массив.
Обратите внимание, что эта концепция похожа на Redux и на то, как она предоставляет хранилище для вашего компонента верхнего уровня и всех его дочерних элементов. Нам просто нужно создать отдельных поставщиков для каждого редуктора, потому что у нас нет глобального хранилища, как Redux.
Шаг 3: useContext
После того, как мы настроили Провайдеров, мы можем получить доступ к значению, которое мы дали Провайдеру через useContext
. Мне нравится думать о useContext
как о чем-то похожем на метод подключения Redux, в котором рассматриваемый компонент теперь имеет доступ к состоянию и метод диспетчеризации для обновления состояния.
Ниже мы используем useContext
в компоненте TestCase
. Полный код можно найти на этом GitHub.
В строке 7 мы useContext
. Вы вызываете его, передавая созданный вами контекст, которым в нашем случае является TestCaseContext
. Если вы заключили компонент или один из его родительских компонентов в Context.Provider
, возвращаемое значение будет равно значению, которое вы передали поставщику. В нашем случае это массив, содержащий testCase
и dispatchToTestCase
. Здесь мы деструктурируем testStatement
и операторы из testCase
, потому что нам не нужен доступ к другим значениям в testCase
.
Давайте посмотрим, как мы отправляем действие редуктору в строке 10. Все, что нам нужно сделать, это вызвать dispatchToTestCase
, чтобы отправить объект действия (возвращаемое значение создателя действия) редуктору.
В заключение
На этом этапе вы можете спросить: «С доступными мне хуками и контекстом, нужно ли мне сейчас использовать Redux?»
Что ж, вот некоторые вещи, которые я пропустил в Redux:
- Отладка путешествия во времени! Я возвращаюсь к консоли и регистрирую свой редуктор.
- Отсутствие единого источника истины, только несколько редукторов.
- Обертывание компонента в
Context.Provider
запускает повторную визуализацию обернутого компонента и всех его дочерних элементов, когда предоставленные изменения (по сравнению с методом подключения Redux, автоматически преобразующим компонент вPure.Component
, который предотвращает повторное отображение).
Было приятно удалить много кода с помощью хуков и контекста и уменьшить размер приложения за счет того, что не нужно устанавливать библиотеки redux
и react-redux
. Я действительно думаю, что предпочитаю Redux для сложных проектов хукам и контексту по вышеуказанным причинам.
Не стесняйтесь задавать любые дополнительные вопросы в комментарии, и я постараюсь ответить, как только смогу.
Ресурсы
📝 Прочтите этот рассказ позже в Журнале.
👩💻 Просыпайтесь каждое воскресное утро и слушайте самые интересные истории недели в области технологий, которые ждут вас в вашем почтовом ящике. Прочтите информационный бюллетень« Примечательно в технологиях .