Это параллельное сообщение с моей недавней прямой трансляцией« Паттерн «Action Hooks с React Hooks »»

В конце 2018 года были анонсированы React Hooks, и в считанные минуты я знал, что они все изменят. Я начал размышлять над тем, как хуки повлияют на разработку моего приложения, и первые крупные победы были очевидны:

  • Совместная логика
  • Больше нет необходимости в рендеринге или компонентах более высокого порядка
  • Более лаконичный, выразительный и декларативный контроль над такими вещами, как состояние, запоминание и побочные эффекты.
  • Просто функции - намного удобнее, чем компоненты

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

Так что же лежит за пределами того, что мы знаем? Что в конечном итоге позволят нам крючки?

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

Управление состоянием с помощью хуков

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

  • Позвольте мне хранить состояние в очень доступном виде.
  • Помогите мне оперативно подписаться на статус, где я хочу
  • Разрешите мне обновлять состояние любым способом, который подходит для моего варианта использования (setState, immer, reducer и т. Д.)

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

С помощью функции makeStore я мог затем создать новый магазин для своего приложения:

С этого момента я чувствовал себя как дома!

Этот подход быстро доказал мне, что вы можете работать с минимальным объемом кода. Но этот код явно не то, что люди в наши дни поставляют с библиотеками государственного управления, так почему и как можно перейти от чего-то простого, например, нашего государственного завода, к чему-то более сложному?

Подумав об этом подробнее, я вспомнил две функции, которые я еще не реализовал в своем магазине:

  • Оптимизация производительности (вычисленные значения, мемоизация, обнаружение изменений)
  • Механизмы обновления (действия, методы, мутаторы и т. Д.)

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

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

Хорошим примером этого является то, как сначала я подумал, что было бы разумно принять некоторые действия в самом хранилище, которые могли бы изменить хранилище при вызове:

Привязка этих действий к хранилищу позволит мне создавать и вызывать их следующим образом:

Я довольно часто сталкивался с этим на практике с более мелкими и более молодыми государственными менеджерами, и хотя поначалу это казалось довольно умным, это привело к множеству других сложных вопросов:

  • Как я могу выполнять асинхронные действия?
  • Что делать, если мне нужен доступ к другой информации, которой нет в магазине, например к LocalStorage или маршрутизатору?

На оба эти вопроса сразу было очень сложно ответить.

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

Как я сюда попал? Почему я пытаюсь решить эту проблему? Все шло отлично, пока я не попытался интегрировать внешние данные в свой менеджер состояний!

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

Я решил, что если мне действительно нужны мощные возможности интеграции в моем магазине, мне нужно держаться как можно дальше от промежуточного программного обеспечения и пользовательских API. Но что еще я мог сделать, чтобы добиться того, чего хотел? Я был в тупике.

С крючками. Долой абстракции.

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

Но на этот раз все было по-другому ... У меня были крючки!

Ждать…

Что, если действия и промежуточное ПО - это просто перехватчики ?!

Думаю об этом:

  • Хуки, как и действия, могут обеспечивать практически любую функциональность независимо от того, где они используются в дереве компонентов.
  • У хуков есть доступ к контексту, жизненному циклу и платформе без дополнительных затрат.
  • Хуки можно бесконечно компоновать, поэтому я мог инкапсулировать и импортировать любые внешние функции, которые мне нужны, без написания промежуточного программного обеспечения или кода интеграции между службами, которые они используют.

Хуки становятся действиями, промежуточным программным обеспечением и, в конечном итоге, основным уровнем интеграции между несвязанными функциями.

Я сразу решил, что мне нужно выделить свои «действия магазина» в их собственные хуки:

Затем я мог бы повторно использовать эти хуки для создания других хуков действий. Это зацепка! О, а асинхронные действия? Легко.

Затем я поработал с другими шаблонами управления состоянием, такими как пространство имен и суб-хранилища:

Было так легко перемещать вещи в соответствии с моими потребностями! Но в моей голове все еще оставался вопрос о вычисленных значениях ...

«Как я могу реализовать что-то вроде Reselect?»

Мемоизированные селекторы (и такие инструменты, как Reselect) - это просто функции, которые кэшируют свой последний результат на основе параметров, которые вы им передаете. Если параметры изменяются, результат функции пересчитывается и временно кэшируется.

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

const computedValue = useMemo(() => a + b, [a, b])

При изменении a или b computedValue будет пересчитан!

Подобно традиционной мемоизированной функции, useMemo будет пересчитывать функцию, которую вы ей передаете, только при изменении охранников (массив значений после функции). Так почему бы не использовать useMemo вместо Reselect?

Однако я знал, что для иллюстрации этого потребуется немного больше, чем счетчик. Так что бери задачи!

С помощью вышеприведенного шаблона я заметил, что могу продолжать составлять крючки вместе, чтобы сформировать тип шаблона селектора:

Хорошо, это было круто. Вперед в следующую битву! Как насчет интеграции с другими библиотеками или хуками? Что ж, казалось, что это и ежу понятно:

Без проблем! К этому моменту я чувствовал себя непобедимым с этим шаблоном, тем более что он не полагался на какую-либо специальную библиотеку, а только на React. Я чувствовал себя так, как будто только что пережил какое-то откровенное возрождение, основанное на крючках.

Хуки - это будущее React

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

Мои прогнозы на 2019 год:

  • Государственные библиотеки либо примут хуки в качестве основной части своего API, либо постепенно самоустранятся, и разработчики будут либо:
  • Построить собственное государственное управление, или
  • Переход от библиотек управления состояниями без перехвата к библиотекам с перехватом
  • Хуки станут основной формой управления, подписки и обновления состояния приложения в приложениях React.
  • Хуки станут универсальным интеграционным слоем между всем, что связано с React.
  • Большие монолитные библиотеки начнут экспортировать более мелкие составные хуки.

Мой вызов тебе:

  • Создайте свой собственный глобальный менеджер состояний с помощью хуков
  • Напишите собственный хук, который инкапсулирует общую логику
  • Преобразование компонента рендеринга для использования хуков
  • Попробуйте useMemo создать конвейер вычисленных значений
  • Преобразуйте библиотеку с открытым исходным кодом, чтобы использовать хуки!

Не могу дождаться, чтобы увидеть, что будет дальше с React Hooks, и что в основном вы собираетесь строить с их помощью. Удачи!

Нравится этот пост?

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

🗞 Просыпайтесь каждое воскресное утро и слышите самые интересные истории, мнения и новости недели, ожидающие в вашем почтовом ящике: Получите примечательный информационный бюллетень›