QueryManager - Complete Guide
Basic Configuration
To create a QueryManager, you need to define:
- Data type (TypeScript interface)
- CRUD methods for API communication
- Optional configurations
import { QueryManager, PaginationResponse } from '@codeleap/query'
// 1. Define your data type
interface User {
id: number
name: string
email: string
created_at: string
}
// 2. Create the manager
const usersManager = new QueryManager<User>({
name: 'users', // Unique name for identification
itemType: {} as User, // Type reference
queryClient: queryClient.client, // TanStack Query client
// Required methods for CRUD operations
listItems: async (limit, offset) => {
const response = await api.get<PaginationResponse<User>>('/users/', {
limit,
offset,
})
return response.data
},
createItem: async (data) => {
const response = await api.post<User>('/users/', data)
return response.data
},
updateItem: async (data) => {
const response = await api.patch<User>(`/users/${data.id}/`, data)
return response.data
},
deleteItem: async (item) => {
await api.delete(`/users/${item.id}/`)
return item
},
retrieveItem: async (id) => {
const response = await api.get<User>(`/users/${id}/`)
return response.data
},
})
Using QueryManager in Components
Complete Hook - use()
The use()
method returns everything you need to manage a list of items:
function UsersScreen() {
const {
items, // Array of users
create, // Function to create user
update, // Function to update user
delete: deleteUser, // Function to delete user
refresh, // Function to refresh list
isRefreshing, // Loading state
getNextPage, // Load next page
getPreviousPage, // Load previous page
itemMap, // Map of items by ID
queries, // Mutation states
} = usersManager.use()
const handleCreateUser = async () => {
const newUser = await create({
name: 'John Silva',
email: 'john@email.com',
})
console.log('User created:', newUser)
}
const handleUpdateUser = async (userId: number) => {
await update({
id: userId,
name: 'Updated Name',
})
}
const handleDeleteUser = async (user: User) => {
await deleteUser(user)
}
return (
<div>
<button onClick={handleCreateUser}>Create User</button>
<button onClick={refresh}>Refresh List</button>
{items.map(user => (
<div key={user.id}>
<h3>{user.name}</h3>
<p>{user.email}</p>
<button onClick={() => handleUpdateUser(user.id)}>
Edit
</button>
<button onClick={() => handleDeleteUser(user)}>
Delete
</button>
</div>
))}
<button onClick={() => getNextPage()}>
Load More
</button>
</div>
)
}
Individual Hooks
You can also use specific hooks for each operation:
Listing - useList()
function UsersList() {
const {
items, // Array of users
query, // TanStack Query object
refresh, // Function to refresh
isRefreshing, // Loading state
itemCount, // Total number of items
getNextPage, // Next page
} = usersManager.useList({
limit: 20, // Items per page
filter: { // Optional filters
status: 'active',
role: 'admin',
},
})
return (
<div>
<p>Total: {itemCount} users</p>
{items.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
)
}
Creation - useCreate()
function CreateUserForm() {
const { create, query } = usersManager.useCreate({
optimistic: true, // Optimistic updates
appendTo: 'start', // Add to beginning of list
})
const handleSubmit = async (formData) => {
try {
const newUser = await create(formData)
console.log('User created:', newUser)
} catch (error) {
console.error('Creation error:', error)
}
}
return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
<button
type="submit"
disabled={query.isPending}
>
{query.isPending ? 'Creating...' : 'Create User'}
</button>
</form>
)
}
Update - useUpdate()
function EditUserForm({ userId }: { userId: number }) {
const { update, query } = usersManager.useUpdate({
optimistic: true, // Show changes immediately
})
const handleUpdate = async (data) => {
await update({
id: userId,
...data,
})
}
return (
<form onSubmit={handleUpdate}>
{/* Form fields */}
<button disabled={query.isPending}>
Save
</button>
</form>
)
}
Deletion - useDelete()
function DeleteUserButton({ user }: { user: User }) {
const { delete: deleteUser, query } = usersManager.useDelete({
optimistic: true, // Remove from list immediately
})
const handleDelete = () => {
if (confirm('Confirm deletion?')) {
deleteUser(user)
}
}
return (
<button
onClick={handleDelete}
disabled={query.isPending}
>
{query.isPending ? 'Deleting...' : 'Delete'}
</button>
)
}
Retrieve Individual Item - useRetrieve()
function UserProfile({ userId }: { userId: number }) {
const { data: user, query, refresh } = usersManager.useRetrieve({
id: userId,
})
if (query.isLoading) return <div>Loading...</div>
if (query.isError) return <div>Error loading</div>
return (
<div>
<h1>{user?.name}</h1>
<p>{user?.email}</p>
<button onClick={refresh}>Refresh</button>
</div>
)
}