Ejemplos completos

Dos listas completas de principio a fin, una con la caché integrada y otra con React Query, sin omitir nada.

Ejemplo completo — sin React Query (caché integrada)

Una lista de admin genérica usando una server action de Next.js, la caché nativa y mutaciones:

// features/users/config.tsx
export const usersConfig = defineListConfig<User>({
	id: 'users',
	title: 'Usuarios',
	search: true,
	pageSize: 20,
	filters: [
		{
			id: 'filters',
			filters: [
				{
					id: 'status',
					field: 'status',
					label: 'Estado',
					type: 'select',
					options: [
						{ value: 'active', label: 'Activo' },
						{ value: 'inactive', label: 'Inactivo' },
					],
					columns: 2, // medio ancho, se sienta junto al siguiente filtro
				},
				{
					id: 'role',
					field: 'role',
					label: 'Rol',
					type: 'select',
					options: [
						{ value: 'admin', label: 'Admin' },
						{ value: 'editor', label: 'Editor' },
					],
					columns: 2,
				},
				{
					id: 'createdAt',
					field: 'createdAt',
					label: 'Alta',
					type: 'date-range',
				},
			],
		},
	],
	table: {
		columns: [
			{ key: 'name', header: 'Nombre' },
			{ key: 'email', header: 'Correo' },
			{ key: 'status', header: 'Estado' },
			{
				key: 'actions',
				header: '',
				render: item => <UserActions user={item} />,
			},
		],
	},
})

// features/users/UserList.tsx
export function UserList() {
	const adapter = serverActionAdapter<User>(async query => {
		const { rows, total } = await listUsersAction(query)
		return { data: rows, total }
	})

	return (
		<ListView
			config={usersConfig}
			adapter={adapter}
			staleTime={60_000} // caché integrada: mantener respuestas por 1 minuto
			toolbarActions={[
				{
					label: 'Nuevo usuario',
					onClick: () => openCreateModal(),
				},
			]}
		/>
	)
}

// features/users/UserActions.tsx
import { useListRefresh } from 'listkit'

function UserActions({ user }: { user: User }) {
	const refresh = useListRefresh()

	const handleDelete = async () => {
		await deleteUserAction(user.id)
		refresh() // invalida la caché integrada y refetchea
	}

	return <button onClick={handleDelete}>Eliminar</button>
}

Ejemplo completo — con React Query

La misma lista, pero dejando que TanStack Query posea la caché y el refetch en segundo plano:

// features/users/UserList.tsx
import { useQuery } from '@tanstack/react-query'
import type { UseListDataHook } from 'listkit'

const useUsersListData: UseListDataHook<User> = (
	adapter,
	query,
	refreshToken
) => {
	const { data, isLoading, error } = useQuery({
		queryKey: ['users', 'list', query, refreshToken],
		queryFn: () => adapter.fetch(query),
		staleTime: 5 * 60 * 1000,
	})

	return {
		data: data?.data ?? [],
		total: data?.total ?? 0,
		isLoading,
		error,
	}
}

export function UserList() {
	const adapter = serverActionAdapter<User>(async query => {
		const { rows, total } = await listUsersAction(query)
		return { data: rows, total }
	})

	return (
		<ListView
			config={usersConfig}
			adapter={adapter}
			useListData={useUsersListData} // React Query toma el control
			toolbarActions={[
				{
					label: 'Nuevo usuario',
					onClick: () => openCreateModal(),
				},
			]}
		/>
	)
}

On this page