data-client-react
SkillMediaLets your agent write React code that fetches, updates, and renders remote data using Data Client hooks.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the data-client-react skill
About this capability
Use @data-client/react hooks for data fetching, mutations, and rendering - useSuspense, useFetch, useQuery, useCache, useLive, useDLE, useSubscription, useController, DataProvider, AsyncBoundary, useLoading, useDebounce. Use when reading/rendering remote data, triggering mutations, doing optimistic
What this skill tells your AI
The instructions your AI receives, as published by reactive/data-client in .agents/skills/data-client-react/SKILL.md and read by ahel’s review.
Rendering
// GET https://jsonplaceholder.typicode.com/todos/5
const todo = useSuspense(TodoResource.get, { id: 5 });
// GET https://jsonplaceholder.typicode.com/todos
const todoList = useSuspense(TodoResource.getList);
// GET https://jsonplaceholder.typicode.com/todos?userId=1
const todoListByUser = useSuspense(TodoResource.getList, { userId: 1 });
// subscriptions with polling, websockets or SSE
const todo = useLive(TodoResource.get, { id: 5 });
// without fetch
const todo = useCache(TodoResource.get, { id: 5 });
const todo = useQuery(Todo, { id: 5 });
// fetch without Suspense - returns { data, loading, error }
const { data, loading, error } = useDLE(TodoResource.get, { id: 5 });
// subscribe without Suspense (use with useSuspense or useDLE)
useSubscription(TodoResource.get, { id: 5 });
// parallel fetches with React.use()
const postPromise = useFetch(PostResource.get, { id });
const commentsPromise = useFetch(CommentResource.getList, { postId: id });
const post = use(postPromise);
const comments = use(commentsPromise);
For API definitions (like TodoResource), apply the skill "data-client-rest".
Mutations
const ctrl = useController();
// PUT https://jsonplaceholder.typicode.com/todos/5
const updateTodo = todo => ctrl.fetch(TodoResource.update, { id }, todo);
// PATCH https://jsonplaceholder.typicode.com/todos/5
const partialUpdateTodo = todo =>
ctrl.fetch(TodoResource.partialUpdate, { id }, todo);
// POST https://jsonplaceholder.typicode.com/todos
const addTodoToBeginning = todo =>
ctrl.fetch(TodoResource.getList.unshift, todo);
// POST https://jsonplaceholder.typicode.com/todos?userId=1
const addTodoToEnd = todo => ctrl.fetch(TodoResource.getList.push, { userId: 1 }, todo);
// DELETE https://jsonplaceholder.typicode.com/todos/5
const deleteTodo = id => ctrl.fetch(TodoResource.delete, { id });
// GET https://jsonplaceholder.typicode.com/todos?userId=1&page=2
const getNextPage = (page) => ctrl.fetch(TodoResource.getList.getPage, { userId: 1, page })
Helpful hooks
const [handleSubmit, loading, error] = useLoading(
async data => {
const post = await ctrl.fetch(PostResource.getList.push, data);
navigateToPost(post.id);
},
[ctrl],
);
const [query, setQuery] = React.useState('');
const handleChange = e => setQuery(e.currentTarget.value);
const [debouncedQuery, isPending] = useDebounce(query, 200);
return (
<AsyncBoundary fallback={<Loading />}>
<IssueList query={debouncedQuery} owner="facebook" repo="react" />
</AsyncBoundary>
)
Components
Prefer using AsyncBoundary for error handling and loading states unless the codebase has
a custom AsyncBoundary that already combines Suspense and ErrorBoundary.
Its props are fallback, errorComponent, and errorClassName and listen. It can be used to wrap any component that fetches data.
<AsyncBoundary listen={history.listen}>
<TodoList />
</AsyncBoundary>
Type-safe imperative actions
Controller is returned from useController(). It has:
ctrl.fetch(), ctrl.fetchIfStale(), ctrl.expireAll(), ctrl.invalidate(), ctrl.invalidateAll(), ctrl.setResponse(), ctrl.set(),
ctrl.setError(), ctrl.resetEntireStore(), ctrl.subscribe(), ctrl.unsubscribe().
Programmatic queries
const queryRemainingTodos = new Query(
TodoResource.getList.schema,
entries => entries.filter(todo => !todo.completed).length,
);
const allRemainingTodos = useQuery(queryRemainingTodos);
const firstUserRemainingTodos = useQuery(queryRemainingTodos, { userId: 1 });
const groupTodoByUser = new Query(
TodoResource.getList.schema,
todos => Object.groupBy(todos, todo => todo.userId),
);
const todosByUser = useQuery(groupTodoByUser);
Browser Debugging (Chrome DevTools MCP)
To inspect store state, track dispatched actions, or invoke
Controller methods from a browser MCP (user-chrome-devtools),
see devtools-debugging. Uses globalThis.__DC_CONTROLLERS__
available in dev mode.
Managers
Custom Managers allow for global side effect handling. This is useful for webosckets, SSE, logging, etc. Always use the skill "data-client-manager" when writing managers.
Best Practices & Notes
- useDebounce(query, timeout) when rendering async data based on user field inputs
- [handleSubmit, loading, error] = useLoading() when tracking async mutations
- Prefer smaller React components that do one thing
- Co-locate data bindings: call useSuspense/useDLE/useCache/useQuery in the component that renders the data — don't prop drill
- Don't hide data bindings inside custom hooks: wrapping them obfuscates a component's data dependencies and couples data logic to view code, causing drift. Put tightly coupled data transformations in a
Queryschema (with the data model, e.g.src/resources/) so they stay reusable and evolve independently of views
References
For detailed API documentation, see the references directory:
- useSuspense;_pagination.md - Fetch with Suspense
- useFetch - Fetch for React.use() and parallel loading
- useQuery - Read from cache without fetch
- useCache - Read from cache (nullable)
- useLive;_useLive.md - Fetch + subscribe to updates
- useDLE - Fetch without Suspense (returns data/loading/error)
- useSubscription - Subscribe to updates (polling/websocket/SSE)
- useController - Access Controller
- Controller - Imperative actions
- AsyncBoundary;_AsyncBoundary.md - Error/loading boundary
- useLoading;_useLoading.md - Track async mutation state
- useDebounce - Debounce values
- DataProvider - Root provider
- data-dependency - Rendering guide
- mutations;_VoteDemo.md - Mutations guide
- Actions - Store action types (FETCH, SET, etc.)
- devtools-debugging - Debug with Chrome DevTools MCP
ALWAYS follow these patterns and refer to the official docs for edge cases. Prioritize code generation that is idiomatic, type-safe, and leverages automatic normalization/caching via skill "data-client-schema" definitions.
Signals
- GitHub stars
- 2k
- Forks
- 99
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
data-client-react- Source
- github.com/reactive/data-client