Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.
Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support
Last updated 1 month, 1 week ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month, 3 weeks ago
Композиция
Честно говоря, все очень плохо. У нас отсутствует возможность композиции фич над примитивом состояния практически во всех реактивных библиотеках.
Простой пример. Можно ли написать библиотеку, которая будет сохранять и восстанавливать данные localStorage для какого-то реакт хука? Да? Вы не поняли, я прошу не написать такой хук, у меня уже есть какой-то хук из UI-kit'а, как мне заперсистеть его данные? Внезапно, такая простая задача не решается вовсе, или решается через доп состояния и лишние реренды \ глитчи синхронизации между ними.
```
const [persistedState, setPersistedState] = useLocalStorage('KEY')
const [state, setState] = useMyComponentState({ initState: persistedState })
useEffect(() => { setPersistedState(state) }, [state])
```
(справедливости ради, вы можете вместо useEffect переназначить setState, но это в данном конкретном случае, иногда модель только отдает данные, но не принимает)
Первое срабатывание useEffect будет в никуда, но это не проблема. Проблема - то что не все такие хуки принимают initState.
Ну ладно, а как теперь валидацию сверху накрутить? Такой параметр библиотека уже не принимает. Привет третее состояние и еще эффекты! Уфф...
Что же делать? Нужны заранее подготовленные интерфейсы расширения, которые позволяют внедрять системную логику в состояние, которое уже потом используется логикой доменной. В каком-нибудь MobX при использовании классов вы можете применять декораторы, но они не стандартизированны...
В реатоме, как вы понимаете, эта проблема уже решена. У нас есть апи операторов, котое позволяет после создания состояния \ экшена навесить что-то сверху. А каждый оператор, благодаря открытости внутренней схемы каждого атома, может добавить что нужно.
Не всегда, конечно, получается сделать все абсолютно модульно. Но вот хороший пример, у нас есть withCache
, который позволяет кешировать данные асинхронных запросов с большим набором опций и настроек. В какой-то момент потребовалась возможность персистеть этот кеш. А персистеть куда? У реатома уже есть адаптеры к: localStorage, indexedDB, BroadcastChannel (для воркеров или табов), а в будущем будет для AsyncLocalStorage (react-native) и другие. Все они сделаны с одним интерфейсом расширения и это позволило просто добавить в withCache
опцию withPersist
, которая принимает и передает нужно расширение нужному атому. В других библиотеках или собственных реализациях вам бы пришлось перепахивать огромную кучу кода, дублируя его или меняя его интерфейсы. У нас же все уже расчитано :)
Вот, кстати, очень интересная модель для знакомства с фичами реатома: код. Все "with*" - это операторы доп фич над создаваемой базовой сущностью, которые могут быть использованы в разных местах и фичах без проблем. Но и сама по себе модель очень интересна: фильтры храняться в урле, а пагинация сбрасывается при смене строки поиска. Попробуйте реализовать эту логику на других библиотеках и удивитесь как много кода это требует и какие потенциальные баги несет.
Кстати, эта модель прекрасно работает как в React, так и во Vue, попробуйте 😏
Несколько апдейтов:
В доки кор пакета добавлено описание фикса гета \ спая юниона атомов
https://www.reatom.dev/package/core/#unions (не запаблишено фикс версией, т.к. там есть брейк для очень редкого случая)
В @reatom/npm\[email protected]
исправлена проблема с hmr для reatomComponent
Обновлены примеры react-search и vue-search, убрана ссылка на отдельный файл, ломающая StackBlitz, а так же добавлены новые фичи! Паттерн сброса одних опций при смене других - достаточно популярен, но реализуется, обычно, криво (влечет к временным ошибочным состояниям). В реатоме withComputed
это прекрасно позволяет сделать, а isInit
позволяет гарантировать корректное применение персиста, что в некоторых фреймворках вовсе невозможно или проблематично.
Примеры с этой же моделью было бы хорошо сделать для солида и свелта, присылайте ваши ПРы!
Небольшие апдейты по докам:
Продвинутый пример написания собственного оператора (withReadyAtom)
Небольшой интерактив, высскажите, пожалуйста, свое мнение :)
В первом реатоме стейты автоматически чистились после всех отписок. Сейчас это выглядело бы как onDisconnect(anAtom, anAtom.reset)
вообще на всех атомах. Это было удобно в большей части кейсов, но не удобно и не явно в некоторых запутанных кейсах, когда есть быстре ремаунты одного или разных компонентов использующих один и тот же атом. Возможно, было бы практичнее повесить ьна эту механику дебаунс и это решило часть проблем.
Что вы об этом думаете? Как вы менеджите актуальность ваших стейтов? Кажется, самый популярный паттер - фабрика, инстанциирующаяся в useMemo родительского компонента или контекста. Решение лучше - атомизация сразу при получении данных извне (при получении новых данных - пересоздаем инстансы). Еще лучше - computed factory.
А вы какими паттернами пользуетесь? Вам чего-то не хватает?
Автоматическая инвалидация ресурса
reatomResource удобен для описания асинхронных данных зависящих от локальных состояний (фильтров \ урла). Но что на счет инвалидации при обновлении удаленного ресурса?
Например, у нас есть список элементов, и кнопка удаления элемента, как описать рефетч ресурса при успешном выполнении экшена удаления?
Самый простой способ - внутрь самого deleteThing
после авейта апишки вставить thingsResource(ctx)
.
Это хороший способ, но не всегда он является элегантным, особенно если deleteThing
создается кодгеном и подлезть в его исходники невозможно. Конечно, на такой случай у нас есть onCall
и вы можете написать deleteThing.onFulfill.onCall(thingsResource)
. С хуками вы можете дизайнить любые ваши состояния и экшены как бы замкнутыми и изолированными, но с возможностью навесить дополнительную логику сверху, при необходимости. Прелести композиционных примитивов ?
Но эту задачу можно решитьь еще лучше!
Хуки лучше использовать для библиотечного кода и стараться не пропускать их в бизнесовый код. Он должен быть максимально простым и единообразным, поэтому все что может быть написано с помощью spy
- должно быть написано с помощью spy
!
Напомню, от горячего onChange
стоит отказываться в пользую ленивого reaction!
А что же с onCall
? Это мелкая обертка над onChange, а action - обертка на atom гарантирующая временность стейта вызова (params и payload). Поэтому его так же можно заменить на spy! Когда вы спаите экшен (обычный или из reatomAsync - не важно), реатом подписывает текущий компьютед на вызов этого экшена. Поэтому, что бы подписать инвалидацию ресурса на какой-то экшен, достаточно сделать так.
```
const thingsResource = reatomResource(async (ctx) => {
ctx.spy(deleteThing.onFulfill)
const params = ctx.spy(thingsParamsAtom)
return ctx.schedule(() => fetch(...params))
}, 'thingsResource').pipe(withDataAtom([]))
```
И у этого подхода есть преимущества над onCall. Если удаление случиться прямо с таблицы которая сейчас отображается (ctx.spy(thingsResource.dataAtom)
) - рефетч будет вызван сразу после окончания промиса на удаление. Но если вы зашли в карточку элемента и там выполнили удаление, рефетч случиться только когда пользователь вернется на страницу со списком элементов, потому что spy ленивый и на карточке элемента ресурс не используется (карточка должна фетчиться отдельным экшеном / ресурсом).
Ой что это у нас ~~в 4 утра~~ год спустя вылезло : https://www.reatom.dev/package/effects/#reaction
reatomResource - реактивное получение данных. reaction
- реактивное отправление данных. Ну типа.
Реакция должна заменить onChange в коде логики (для утилит ещё нужна будет), потому что сейчас это:
1) Еще один способ сделать одно и тоже.
2) Делает код более менее линейным.
3) Не очевидно работает на компьютедах.
4) Совсем странный код получается при необходимости обрабатывать несколько источников (см. мотивацию https://www.reatom.dev/package/async/#reatomresource).
Reatom
effects
Reatom for effects
withVariables
В чате спросили как сделать оптимистик апдейт аналогично тенстаку: https://tanstack.com/query/latest/docs/framework/react/guides/optimistic-updates#via-the-ui
Держите простой оператор withVariables который к асинк апдейту (мутации) добавляет соответствующий атом variables
.
```
import { AsyncAction, atom, Atom, withAssign, withComputed } from "@reatom/framework"
export type WithVariables = T & {
variables: Atom[1]>
}
export const withVariables = (
initState: State,
): ((anAction: T) => WithVariables) =>
withAssign((target, name) => ({
variables: atom(initState, ${name}.variables
).pipe(
withComputed((ctx, state = initState) => {
ctx.spy(target).forEach(({ params }) => {
state = params[0]
})
ctx.spy(target.onSettle).forEach(() => {
state = initState
})
return state
}),
),
}))
```
Обратите внимание, что апдейт атома variables ленивый, если на него может не быть подписки, но его все равно нужно обновлять - добавьте пару onCall на соответствующие экшены, как рассказано тут: https://t.me/reatom_ru_news/249
Список основных изменений в v4, релиз планируется в течении пары месяцев:
https://github.com/artalar/reatom/issues/841
Есть изменения, миграцию которых можно автоматизировать кодмодом (раз, два), эти задачи пока ни на кого не назначены, если хотите вписаться в контрибьюшен - эти задачи не должны быть сложны (можно взять какой-нибудь https://github.com/coderaiser/putout)
GitHub
v4 · Issue #841 · artalar/reatom
The upcoming version "4" will feature several changes, but most will be straightforward to migrate. Here is the list of main changes. Publish only an ESM bundle. Store all code in a singl...
Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.
Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support
Last updated 1 month, 1 week ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month, 3 weeks ago