Framework bindings
A query implements effector's @@unitShape protocol, so you can pass it straight to useUnit from effector-react, effector-vue or effector-solid — no wrapper needed.
// React
import { useUnit } from 'effector-react';
function UserCard({ id }: { id: number }) {
const { data, pending, error, refetch } = useUnit(userQuery);
return pending ? <Spinner /> : <div onClick={() => refetch(id)}>{data?.name}</div>;
}<!-- Vue -->
<script setup lang="ts">
import { useUnit } from 'effector-vue/composition';
const { data, pending, refetch } = useUnit(userQuery);
</script>useUnit(query) yields { data, error, status, pending, stale, enabled, params, start, refetch, refresh, reset, cancel }.
useQuery helpers
Thin helpers that add derived booleans (isInitial / isPending / isDone / isFail):
// React — effector-refetch/react
import { useQuery } from 'effector-refetch/react';
const { data, isPending, isFail, error, start } = useQuery(userQuery);
useEffect(() => start(id), [id]); // queries never auto-start<!-- Vue — effector-refetch/vue (returns refs) -->
<script setup lang="ts">
import { useQuery } from 'effector-refetch/vue';
const { data, isPending, isDone, start } = useQuery(userQuery);
</script>// Solid — effector-refetch/solid (returns accessors — call them)
import { useQuery } from 'effector-refetch/solid';
function UserCard(props: { id: number }) {
const { data, isPending, isFail, start } = useQuery(userQuery);
start(props.id); // queries never auto-start
return <div>{isPending() ? 'Loading…' : data()?.name}</div>;
}React works with <Provider value={scope}>, Vue with the EffectorScopePlugin, Solid with effector-solid's <Provider> — all for SSR / fork. Bindings require the matching optional peers (react+effector-react / vue+effector-vue / solid-js+effector-solid).
Refetch on mount
useQuery (all three frameworks) takes an options object — refetchOnMount refetches the query with its last params when the component subscribes:
useQuery(userQuery, { refetchOnMount: true }); // refetch only if data is stale
useQuery(userQuery, { refetchOnMount: 'always' }); // refetch every mountIt's a no-op until the query has run at least once (status !== 'initial') and is enabled — it never starts a query that has no params yet. true needs a cache.staleAfter to have a notion of staleness; 'always' ignores it.
Suspense (React)
useSuspenseQuery returns the data directly (never null): it auto-starts the query, suspends the nearest <Suspense> while loading, throws to the nearest Error Boundary on failure, and returns the data when done.
import { Suspense } from 'react';
import { useSuspenseQuery } from 'effector-refetch/react';
function UserName({ id }: { id: number }) {
const user = useSuspenseQuery(userQuery, id); // suspends until ready
return <span>{user.name}</span>;
}
function Page({ id }: { id: number }) {
return (
<ErrorBoundary fallback={<p>Failed to load</p>}>
<Suspense fallback={<Spinner />}>
<UserName id={id} />
</Suspense>
</ErrorBoundary>
);
}This is for client-side Suspense: reads and triggers are scope-aware, but the settle signal is observed globally, so use it with fork outside of concurrent SSR streaming.