Авто-рефетч и поллинг
Поллинг — refetchInterval
Перезапрос по таймеру, пока запрос запущен и включён:
const stats = createQuery({ effect: fetchStatsFx, refetchInterval: 5000 }); // каждые 5с
stats.start();После каждого завершения (успех или ошибка) запрос ждёт refetchInterval мс и делает refresh с последними параметрами (минуя кэш). Пауза, пока $enabled = false, остановка на reset, и всё fork-корректно (каждый scope поллит независимо). Интервал может быть реактивным — передайте Store<number> и меняйте на лету (например, чаще, пока вкладка активна):
createQuery({ effect: fx, refetchInterval: $pollMs });По фокусу окна / реконнекту
Opt-in, только браузер, tree-shakeable:
import { refetchOnWindowFocus, refetchOnReconnect } from 'effector-refetch';
const stop1 = refetchOnWindowFocus(userQuery);
const stop2 = refetchOnReconnect(userQuery);
// вызовите stop1() / stop2(), чтобы отписатьсяОба перезапрашивают с последними параметрами запроса, только если он уже запускался и включён. Они читают no-scope-стор, поэтому рассчитаны на одно-клиентское приложение; для scope-приложений дёргайте query.refetch сами через scopeBind.
Offline / сетевой режим
createNetworkBarrier() — это barrier, который блокируется, пока браузер офлайн, и разблокируется при реконнекте. Подключите его к запросам — и их прогоны встают на паузу при потере сети, а затем сами продолжаются при её возврате, без обвязки на каждый запрос:
import { createNetworkBarrier, refetchOnReconnect } from 'effector-refetch';
const offline = createNetworkBarrier();
const userQuery = createQuery({ effect: fetchUserFx, barrier: offline });
// или на всю группу: createQueryFactory({ barrier: offline })
offline.$online; // Store<boolean> — для баннера «вы офлайн»
refetchOnReconnect(userQuery); // опционально: ещё и обновить уже загруженные данные
offline.stop(); // отвязать слушатели online/offline при размонтированииПрогон, запущенный офлайн, висит в pending (тело эффекта не вызывается), пока сеть не вернётся. Только браузер — на сервере барьер остаётся открытым (онлайн).
Рефетч при изменении источника — keepFresh
Держите запрос свежим относительно внешнего состояния (фильтры, локаль, текущий пользователь): keepFresh перезапрашивает его с последними параметрами при изменении стора-source.
import { keepFresh } from 'effector-refetch';
keepFresh(productsQuery, { source: $filters }); // или source: [$filters, $locale]No-op, пока запрос не запускался (status !== 'initial') и пока он disabled. Отличается от refetchInterval (по времени) — это по зависимости. (Если значение источника должно реально менять запрос — прокидывайте его в параметры через connectQuery / sample в start.)
Триггеры web-API (@withease/web-api)
Трекеры @withease/web-api реализуют протокол @@trigger, поэтому подключаются в keepFresh({ triggers }) напрямую — без адаптера:
import { trackPageVisibility, trackNetworkStatus } from '@withease/web-api';
import { keepFresh } from 'effector-refetch';
const network = trackNetworkStatus();
// рефетч, когда вкладка снова становится видимой (трекер фаерит свой `visible`)
keepFresh(dashboardQuery, { triggers: [trackPageVisibility()] });
// …или на любое обычное событие, которое отдаёт трекер
keepFresh(dashboardQuery, { triggers: [network.online] });Сторы трекеров годятся в остальные слоты: гейтите запрос пока офлайн через enabled, или используйте стор трекера как source:
createQuery({ effect: fx, enabled: network.$online });Это пересекается со встроенными refetchOnWindowFocus / refetchOnReconnect / createNetworkBarrier выше — для типовых случаев берите встроенные, а @withease/web-api — когда нужно больше сигналов (геолокация, media query, ориентация экрана, …) за тем же @@trigger API.
Композиция с patronum
Триггеры запроса — обычные события effector, поэтому их можно гонять любым оператором patronum — без специального API:
import { interval, debounce, throttle } from 'patronum';
// debounce поиска по мере ввода
debounce({ source: queryChanged, timeout: 300, target: searchQuery.start });
// свой поллинг с управлением start/stop
const { tick } = interval({ timeout: 10_000, start: pageOpened, stop: pageClosed });
sample({ clock: tick, source: searchQuery.$params, target: searchQuery.refetch });
// throttle кнопки обновления
throttle({ source: refreshClicked, timeout: 1000, target: dashboard.refresh });Для типового случая используйте встроенный refetchInterval; берите patronum, когда нужны явные start/stop, debounce или throttle.