Этот волшебный объект запечатывает внутреннюю реализацию библиотеки, чтобы разработчики не могли с ней связываться. В этом посте мы узнаем больше об исходном объекте.
Этот пост является частью следующей серии постов в блоге:
- async-states: библиотека управления состоянием
- асинхронные состояния: использование реакции
- асинхронные состояния: исходный объект
- асинхронные состояния: производитель
- асинхронные состояния: расширенные концепции
- асинхронные состояния: vs. response-query vs redux vs recoil
- реагировать-асинхронные-состояния: 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
из предыдущей схемы.
Заключение
Без сомнения, исходный объект — это волшебство в библиотеке: он не дает вам случайным образом манипулировать экземпляром внутреннего состояния, предоставляя вам полный контроль над ним, а также может использоваться библиотекой в качестве «идентификатора состояния».
Источник обычно связан с производителем, который является еще одним важным элементом в библиотеке. В следующем посте поговорим о силе продюсера и о том, как писать хорошие.