Skip to main content

Advanced Features

Custom Effect Hook

const usersManager = new QueryManager<User>({
// ... configurations
useListEffect: (listQuery) => {
// Custom implementation for refresh
useQueryListRefresh(listQuery, {
staleTime: 5000 // 5 seconds
})

// Or custom logic
useEffect(() => {
const interval = setInterval(() => {
listQuery.refreshQuery(true) // silent refresh
}, 30000) // every 30 seconds

return () => clearInterval(interval)
}, [])
},
})

CodeleapQueryClient - Advanced Methods

Creating Basic Queries

// Simple query
const profileQuery = queryClient.queryKey(['profile'], {
queryFn: async () => {
const response = await api.get('/profile/')
return response.data
},
})

// Using in component
function Profile() {
const { data, isLoading } = useQuery({
queryKey: profileQuery.key,
})

const handleRefresh = async () => {
const newData = await profileQuery.refresh()
console.log('Updated data:', newData)
}

return (
<div>
{isLoading ? 'Loading...' : data?.name}
<button onClick={handleRefresh}>Refresh</button>
</div>
)
}

Query Polling

Polling allows you to execute a query repeatedly until a stop condition:

const startPolling = async () => {
const results = await profileQuery.poll<string[]>({
interval: 2000, // 2 seconds
leading: false, // Don't execute immediately
initialData: [], // Initial data
async callback(query, count, previousResults) {
const currentName = query.state.data?.name
const allNames = [...(previousResults || []), currentName]

console.log(`Iteration ${count}:`, allNames)

// Stop condition
return {
stop: count >= 5 || currentName?.includes('admin'),
data: allNames,
}
},
})

console.log('Final polling result:', results)
}

Change Listeners

const removeListener = profileQuery.listen((event) => {
if (event.type === 'updated') {
console.log('Profile updated:', event.query.state.data)
}
})

// Remove listener when no longer needed
// removeListener()

Dynamic Query Keys

For queries that depend on parameters:

// Defining dynamic key builder
const userQueryBuilder = (userId: number) => ['user', userId]

// Creating dynamic proxy
const userQueries = queryClient.dynamicQueryKey<User, [number]>(
userQueryBuilder
)

// Using
const handleGetUser = async (userId: number) => {
const user = await userQueries.ensureData(userId)
console.log('User:', user)

// Refreshing specific user
const refreshedUser = await userQueries.refresh(userId)

// Polling specific user
const pollResults = await userQueries.poll(userId, {
interval: 1000,
callback: async (query, count) => ({
stop: count > 3,
data: query.state.data,
}),
})
}

Advanced Configurations

Configuration Options

const manager = new QueryManager<Item>({
name: 'items',
itemType: {} as Item,
queryClient: client,

// Optional configurations
limit: 25, // Default per page
generateId: () => Date.now(), // Custom ID generator
keyExtractor: (item) => item.slug, // Custom key extractor

// Default configurations for operations
creation: {
optimistic: true,
appendTo: 'start',
},
update: {
optimistic: true,
},
deletion: {
optimistic: false, // Safer for deletions
},

// Initial metadata
initialMeta: {
category: 'default',
permissions: ['read'],
},
})

TanStack Query Integration

The library is fully compatible with TanStack Query. You can use both simultaneously:

// Using TanStack Query directly
const { data } = useQuery({
queryKey: ['custom-query'],
queryFn: () => api.get('/custom-endpoint/'),
})

// Using Codeleap manager
const { items } = manager.useList()

// Accessing underlying QueryClient
const queryClient = manager.queryClient
queryClient.invalidateQueries(['custom-query'])