En el mundo del desarrollo web moderno, la eficiencia en la gestión de datos es crucial para garantizar el rendimiento y la experiencia del usuario. Vamos a hablar sobre TanStack Query y más específico su versión para React (React Query), una herramienta muy útil que está cambiando la forma en que los desarrolladores gestionan los datos en la web.
Aprenderemos lo básico para poder implementarlo ya en nuestros proyecto y marcar la diferencia mejorando la experiencia de usuario y optimizando la gestión de los datos.
Índice
- ¿Qué es React Query?
- Conceptos
- Ejemplo sin usar React Query
- Usando React Query
- Demostración
- Conclusiones
¿Qué es React Query?
React Query es una biblioteca de gestión de estado y caché. Nos proporciona una manera sencilla y eficiente de realizar consultas de datos, gestionar su estado y mantenerlos actualizados en toda la aplicación.
Con React Query, podemos manejar fácilmente las interacciones con la red y la caché de datos, lo que crea una experiencia al usuario mucho más fluida.
Actualmente, pertenece a un ecosistema llamado TanStack que recopila varias herramientas para React, Vue, Angular y más frameworks. Por lo que muchas explicaciones de este tutorial servirán también si no usas React.
React Query ahora mismo se encuentra en la versión 5. Si te encuentras en otras versiones, la documentación oficial ofrece guías para actualizar a esta versión.
Conceptos
React Query tiene muchos conceptos y funcionalidades pero aquí explicaremos los principales para que ya puedas trabajar con esta biblioteca.
- Queries (Consultas): Realizar consultas de datos asíncronos, obtener y gestionar los resultados de esas consultas.
- Query Keys (Claves de Consulta): Identificadores únicos para cada consulta en React Query. Permiten el seguimiento y la gestión precisa del estado y cache de las consultas.
- Query Functions (Funciones de Consulta): funcione que devuelve ua promesa que debería obtener datos o dar un error.
- Mutations (Mutaciones): Operaciones que modifican datos, como crear, actualizar o eliminar registros, en React Query.
- Query Invalidation (Invalidación de Consultas): Proceso para refrescar datos en la caché de React Query, garantizando que la información mostrada esté actualizada y precisa.
Para ampliar información, consultar la documentación de Tanstack Query (React Query).
Ejemplo sin usar React Query
Siempre que queremos hacer alguna petición de datos o cualquier operación asíncrona en React, tenemos que seguir ciertos pasos como:
- Crear un estado para los datos
- Crear un UseEffect para ejecutar la operación
- Setear los datos.
Si queremos tener controlado cuando está cargando o si hay errores, solemos crear otros estados para estos casos, por lo que al final tendríamos algo como esto en nuestro componente:
function component() {
//...
const [todos, setTodos] = React.useState([])
const [isLoading, setIsLoading] = React.useState(false)
const [error, setError] = React.useState(null)
React.useEffect(() => {
setIsLoading(true)
getAllTodos()
.then(res => setTodos(res) )
.catch(err => setError(err.message))
.finally(() => setIsLoading(false))
}, [])
//...
}
Esto es una forma correcta de manejar este tipo de operaciones, pero siempre que hagamos la misma operación tendrá que volver a ejecutarse y traer de nuevo los datos.
Si queremos trabajarlo de esta manera podríamos crearnos nuestro propio custom hook para poder reutilizarlo y no repetir el mismo código donde le pasaremos la función asíncrona que queremos ejecutar. A la hora de usarlo nos devolverá los datos, si está cargando datos o no y si hay errores.
import React from "react"
export const useCustomQuery = ({queryFunction}) => {
const [data, setData] = React.useState([])
const [isLoading, setIsLoading] = React.useState(false)
const [error, setError] = React.useState(null)
React.useEffect(() => {
setIsLoading(true)
queryFunction()
.then(res => setData(res) )
.catch(err => setError(err.message))
.finally(() => setIsLoading(false))
}, [])
return {data, isLoading, error}
}
Para poder usarlo lo importaremos donde queramos usarlo y le pasamos nuestra función getAllTodos.
const {data: todos, isLoading, error} = useCustomQuery({
queryFunction: getAllTodos
})
Usando React Query
Instalación
npm install @tanstack/react-query
Envolver la app con React Query
En el fichero index.js/main.js donde tenemos el punto de entrada de nuestra aplicación en React, envolveremos el componente ** con el provider que nos ofrece React Query.
import App from "./App";
import {
QueryClient,
QueryClientProvider
} from "@tanstack/react-query";
const queryClient = new QueryClient();
//...
root.render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
)
Hook useQuery
Para poder trabajar con queries, react-query nos proporciona un hook llamado useQuery. Este hook recibirá un objeto de opciones en las que se puede encontrar la query key, query function, etc.
const {data: todos, isLoading, error} = useQuery({
queryKey: ['todos'],
queryFn: getAllTodos,
})
Si nos fijamos, es un hook muy parecido al que hemos creado anteriormente nosotros, pero en este caso nos ofrecerá muchas más opciones y posibilidades aparte de cacheo de los datos que obtenemos.
De esta manera, cuando obtenga los datos por primera vez las siguientes veces que usemos este hook con la misma queryKey, no volverá a traer los datos, ya que los tiene cacheados, lo que nos proporciona una capacidad de mostrar datos al usuario de una manera muy rápida.
Invalidar queries
Se puede dar el caso de que queremos que se vuelva a hacer una petición y traer datos nuevos porque se han cambiado debido a una actualización que hemos hecho nosotros, una actualización por parte de terceros, etc. Para esto tenemos la opción de invalidar queries para que vuelva a realizar la petición.
Para usar la invalidación de queries importaremos useQueryClient primero
import {useQueryClient} from '@tanstack/react-query'
Luego en nuestro componente donde queramos usarlo crearemos una instancia de useQueryClient que será la que tenga el método invalidateQueries. Este recibe un objeto con una propiedad llamada queryKey con el valor de la key que queremos invalidar.
const queryClient = useQueryClient()
queryClient.invalidateQueries({ queryKey: ['todos'] })
Tener en cuenta que si se invalida la query pero los datos que va a obtener siguen siendo los mismo no cambiará ni ejecutará nada.
Mutaciones
Importaremos useMutation de la biblioteca, ya que será el hook que nos permita manejar las mutaciones con React query
import {useMutation} from '@tanstack/react-query'
Para usarlo, este hook recibirá diferentes opciones, en nuestro caso mostramos mutationFn que será nuestra función para crear nuevas tareas y onSuccess que se ejecutará si todo ha ido correctamente.
function component() {
//...
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: async (newTodo) => await postNewTodo(newTodo),
onSuccess: () => {
queryClient.invalidateQueries('todos')
}
})
const handleSubmit = (event) => {
event.preventDefault()
mutation.mutate({title: inputValue, completed: false})
setInputValue('')
}
//...
}
Como vemos en la función que se ejecuta si todo va correcto invalidaremos la query de todos para que vuelva a obtener los datos ya que hemos añadido una tarea nueva.
Demostración
En este apartado veremos la diferencia en la obtención de datos usando React Query y sin usarlo.
Es una simple aplicación que tiene 2 páginas en las que se hace la misma petición de datos donde podremos ver el tiempo que tardan en cargar cuando navegamos entre ellas.
Sin usar React Query
Podemos ver que cada vez que navegamos a una página se vuelve a hacer la petición y tarda en cargar hasta que tengamos todos los datos.
Usando React Query
En este caso se puede ver como después de la primera petición ya no vuelve a cargar datos ya que los tiene cacheado y la obtención de estos es muy rápida, optimizada y genera una experiencia más fluida.
Conclusiones
Hemos podido ver las características principales de React Query. Con esto ya seríamos capaces de usarlo en un proyecto, siendo de mucha utilidad y poco a poco ir ampliando el conocimiento sobre la biblioteca. Esta es una de las razones por las que creo que es una gran biblioteca, ya que con muy poco somos capaces de hacer grandes mejoras en nuestro proyecto.
Es importante también entender que no hay que usarlo siempre, esto podría llegar a meter una complejidad en el proyecto innecesaria y, a lo mejor, sin tener tampoco un gran beneficio. Aquí es donde entra nuestro rol, donde debemos entender el proyecto y valorar si merece la pena o no cachear los datos.
A pesar de esto, creo que es una librería que hoy en día es importante saber para qué sirve, los conceptos y cómo funciona, ya que es recurrente verla en el mundo laboral.
¡Muchas gracias! ??