Пошаговое руководство с реальным примером

Репо для этого материала можно найти по адресу 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 для сложных проектов хукам и контексту по вышеуказанным причинам.

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

Ресурсы

📝 Прочтите этот рассказ позже в Журнале.

👩‍💻 Просыпайтесь каждое воскресное утро и слушайте самые интересные истории недели в области технологий, которые ждут вас в вашем почтовом ящике. Прочтите информационный бюллетень« Примечательно в технологиях .