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

Этот пост является частью следующей серии постов в блоге:

  1. async-states: библиотека управления состоянием
  2. асинхронные состояния: использование реакции
  3. асинхронные состояния: исходный объект
  4. асинхронные состояния: производитель
  5. асинхронные состояния: расширенные концепции
  6. асинхронные состояния: vs. response-query vs redux vs recoil
  7. реагировать-асинхронные-состояния: SSR

План

  • Почему ?
  • Что он содержит?
  • Как это использовать?
  • Как использовать его с React?
  • Возврат useAsyncState

Почему ?

async-states хранит свое состояние в объекте в памяти, в свойстве с именем state, это явно не имеет ничего общего с реагированием.

Это свойство заморожено и скрыто вместе с кучей других свойств в экземпляре состояния, таких как: subcsriptions, locks, latestRun, lanes и многими другими свойствами деталей реализации, которые:

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

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

Для этого в библиотеке используется неприятная техника, если вам интересно, прочитайте здесь!

Следует сохранить то, что source похож на interface, а class, реализующий этот интерфейс, — это state instance. Существует отношение one-to-one между каждым state instance и его source object.

Это позволит внутренним компонентам библиотеки пойти по другому пути, чем то, что предлагает общедоступный API! выйти мощный.

Что он содержит?

Мы видели это раньше в части 1 этой серии:

Как это использовать

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

Создать состояние

Самый простой способ создать экземпляры состояния в библиотеке — через createSource. Вот некоторые примеры:

Примечание. CreateSource имеет две подписи

Итак, к настоящему моменту мы создали несколько общих состояний. Давайте изменим некоторые значения.

Установить значение состояния

Основной способ изменить значение состояния — вызвать метод source.setState:

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

Вот несколько примеров его использования:

Примечание. source.setState можно вызывать везде, он изменит значение состояния, а затем уведомит всех подписчиков.

Запустите производителя

Чтобы запустить производителя, прикрепленного к состоянию, просто: source.run(...args); :

Примечание. Если к вашему штату не подключен производитель, вызов run будет полностью делегирован setState.

Сменить производителя

Смена производителя разрешена, хотя это не всегда хорошая идея, так как вы не будете соблюдать типобезопасность и куча проблем. Но разрешено выполнять абстракции в пространстве пользователя, которые могут исправлять производителя при любом обновлении. Это должно быть хорошо, если производитель создается в замыкании и будет стабильным по типу (хотя args и payload были изобретены, чтобы подавить вашу потребность в этом).

Управление полезной нагрузкой

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

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

Воспроизвести последний запуск

source.replay() воспроизведет последний запуск с неглубокой копией полезной нагрузки, а args будет использоваться в последнем запуске. Вы можете использовать его, например, когда запрос терпит неудачу, и вы показываете пользователю кнопку try again .

Беги и получи обещание к исполнению

runp — это специальная функция, которая принимает args для передачи производителю (точно так же, как run), за исключением того, что она возвращает не функцию abort, а Promise, которая разрешается с любым состоянием, полученным в результате вашего запуска:

Подписаться на обновления

Библиотека также предоставляет функцию subscribe, которая позволяет прослушивать обновления состояния:

Прикрепите прослушиватели событий к экземпляру состояния

Библиотека добавляет систему событий, которую вы можете использовать следующим образом:

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

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

Примечание 2. В будущем можно будет добавить события подписки, связанные с одной подпиской, которые, очевидно, будут удалены при отказе от подписки.

Использование с React

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

Ничего

В этом случае создается пустое состояние и возвращаются его ключ и источник (вместе со всеми остальными свойствами).

let {state, setState} = useAsyncState()

Строка

В этом случае библиотека либо будет использовать состояние с этой строкой как key, если не найдется, то будет создана.

Примечание. Чтобы дождаться этого состояния, используйте:

let {state, setState} = useAsyncState({
  wait: true,
  key: "my-key",
})

Исходный объект

Возможно, вы уже видели это в этой серии сообщений в блоге:

продюсер

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

Объект конфигурации

Объект конфигурации подробно описан в документации, выделим его только здесь, он содержит следующие свойства (все они необязательны):

  • key: string
  • producer: Producer
  • source : если указан источник, он используется
  • Все свойства ProducerConfig: initialValue, skipPendignDelaysMs, cacheConfig, retryConfig ...
  • lazy: boolean если false, подписка будет запускать производителя.
  • autoRunArgs: any[] Аргументы для передачи производителю в случае autoRun
  • condition: boolean | ((currentState) => boolean) : Чтобы решить, запускать ли автоматически или нет
  • payload: Record<string, any> : полезная нагрузка, которая будет объединена в экземпляре с подпиской.
  • wait: boolean : приказывает useAsyncState дождаться состояния, если оно не существует, а не создавать его
  • fork: boolean нужно ли создавать отдельный экземпляр из предусмотренных конфигурацией
  • forkConfig : конфигурация для применения при разветвлении (извините, я не говорил о разветвлениях ранее, но они есть в документации и будут обсуждаться в дополнительных материалах).
  • subscriptionKey: string : Ключ подписки будет виден в devtools.
  • events Объект конфигурации для {change, subscribe} событий, подробнее о них читайте здесь в документации.
  • selector(currentState, cache): DerivedState: возвращаемый state из useAsyncState является возвратом этого селектора.
  • areEqual(prev, next): boolean сравнивает текущую и следующую выбранную часть состояния, нужно ли отображать или нет.

Возврат useAsyncState

Возвращаемое значение useAsyncState содержит все свойства, содержащиеся в источнике, а также:

  • state : фактическое состояние (или результат selector, если он есть)
  • read(suspend: boolean = true, throwError: boolean = true): возвращает state и выдает Promise, если pending, или data, если error (оптимизация одновременных ошибок и границ ошибок)
  • version:number текущая захваченная версия экземпляра состояния
  • lastSuccess последнее успешное значение
  • flags: number
  • source наш исходный объект
  • devFlags декодированный массив flags в режиме разработки
  • onChange() позволяет зарегистрировать change событий для текущей подписки. Это оптимизация для добавления обратных вызовов непосредственно из рендеринга (они будут добавлены позже).

Если вам нравятся диаграммы, вот как все это вписывается:

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

Экземпляр внутреннего состояния также наследуется от BaseSource из предыдущей схемы.

Заключение

Без сомнения, исходный объект — это волшебство в библиотеке: он не дает вам случайным образом манипулировать экземпляром внутреннего состояния, предоставляя вам полный контроль над ним, а также может использоваться библиотекой в ​​качестве «идентификатора состояния».

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