data-client-react
npx skills add https://github.com/reactive/data-client --skill data-client-react
Agent 安装分布
Skill 文档
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 });
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);
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
References
For detailed API documentation, see the references directory:
- useSuspense;_pagination.mdx – Fetch with Suspense
- useQuery – Read from cache without fetch
- useCache – Read from cache (nullable)
- useLive;_useLive.mdx – 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.mdx – Error/loading boundary
- useLoading;_useLoading.mdx – Track async mutation state
- useDebounce – Debounce values
- DataProvider – Root provider
- data-dependency – Rendering guide
- mutations;_VoteDemo.mdx – Mutations guide
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.