Qwik — Custom Hooks

Claves para entender el funcionamiento de los Hooks y como crear los nuestros propios

Anartz Mugika Ledo🤗
12 min readMay 30, 2023

Comenzamos con un nuevo artículo en el que nos vamos a sumergir en un concepto que bajo mi punto de vista es muy importante conocer y dominar.

Vamos a explorar al detalle los custom hooks en Qwik, comprendiendo su estructura, su uso y los beneficios que aportan a nuestros proyectos.

Analizaremos los aspectos a tener en cuenta para crear de manera correcta nuestros custom hooks y posteriormente entraremos a la acción creando varios ejemplos prácticos y paso a paso de diferentes custom hooks, desde los más simples hasta los más avanzados, para que puedas comprender y aplicar esta poderosa técnica en tus propias aplicaciones.

En resumen, los custom hooks son una herramienta valiosa que nos permite construir aplicaciones más eficientes, reutilizables y fáciles de mantener en Qwik (En React también). Con su capacidad para encapsular y compartir la lógica común, nos brindan un enfoque elegante para mejorar la modularidad y la legibilidad de nuestro código. ¿Estáis con ganas de empezar? ¡Seguro que si!

Os recomiendo leer los artículos anteriores en orden y si practicáis, ¡¡mucho mejor!!.

Recordad, que si hay dudas, aun leyéndolo, podéis preguntarlo en los comentarios y sin dudas me gustaría que me comentéis también, para tener feedback.

Todos los artículos publicados del curso los encontraréis en la siguiente lista que iré actualizando semanalmente y estableciendo el orden natural recomendado:

Qwik paso a paso desde 0 al detalle

23 stories

Si queréis recibir notificaciones sobre este contenido y similares, os animo a que os suscribáis a mi lista de correo:

Solo habrá avisos con nuevos contenidos, es decir, nuevos artículos (1–3 máximo a la semana, generalmente 1).

En este artículo trabajaremos con la versión 1.1.4, que es la versión estable que tenemos en la actualidad (30/05/2023).

Contenido del artículo

  • ¿Qué son los custom hooks en Qwik?
  • Aspectos a tener en cuenta para crear nuestros custom hooks
  • Como usar un hook correctamente
  • Primer custom hook en Qwik: useCounter
  • Custom Hook: useTheme
  • Custom Hook: useMousePosition
  • Ideas para crear más custom hooks.
  • Conclusión.

¿Qué son los custom hooks en Qwik?

Los custom hooks en Qwik (como en React) son un tipo de función JavaScript que simula el funcionamiento de los hooks en Qwik.

Los custom hooks en Qwik son muy útiles siempre que tengamos una lógica que se repite entre varios componentes. En estos casos, podemos sacar esta lógica y aplicarla a un custom hook, es decir, una función que ejecute los pasos que necesitamos de manera automática, con lo que reduciremos código, haremos que el código sea más fácil de mantener ante futuros cambios y podríamos usar estos custom hooks en futuros proyectos.

Al no ser funciones cualquiera, los custom hooks en Qwik deben seguir una serie de reglas para ser considerados hooks y no funciones. A continuación, os explicaré cuáles son.

Aspectos a tener en cuenta para crear nuestros custom hooks

Son pocos los aspectos que son importantes tener en cuenta. Os los dejo a continuación:

  • El nombre debe de empezar con la palabra use. Esto sería una convención, más que una regla (aunque “hay que cumplirla”)
  • Se inician dentro de los componentes de Qwik, que estén implementados con la llamada a la función component$. Está es una regla obligatoria
  • Un hook puede llamar a otros hooks, sean los que vienen por defecto y los custom hooks. Detalle a tener en cuenta.

Formato a seguir al definir nombre de la función

La primera regla de los custom hooks en Qwik es que su nombre debe empezar con la palabra use.

Esta convención se crea siguiendo los hooks originales de Qwik. Hasta ahora hemos trabajado con algunos de ellos en artículos anteriores (aunque hay más que podéis encontrar en la documentación oficial) que añadiré sus referencias por los apartados que vienen a continuación:

Esta regla, la del nombre que debe de empezar con use es utilizada en React, por lo que si venís a Qwik teniendo unos conocimientos sólidos de React, prácticamente este paso ya lo tenéis más que asimilado.

Se considera que esto es una regla porque la comunidad ha decidido que es más sencillo reconocer un custom hook cuando sigue esta convención. Esto se estableció en React y se ha implementado también en Qwik, para que sea más fácil trabajar siguiendo las convenciones de la comunidad.

Eso si, en teoría podríamos crear un custom hook con otro nombre (sin el use) sin que nos diese errores ni problemas, pero no es lo recomendable.

Debe de estar englobado dentro de la función component$

Esta si es una regla obligatoria, ya que si no implementamos la ejecución de un hook dentro de un componente de Qwik que realiza la llamada a la función component$ nos va a dar un error en el que básicamente nos dirá:

Code(20): Calling a 'use*()' method outside 
'component$(() => { HERE })' is not allowed.
'use*()' methods provide hooks to the 'component$' state and lifecycle,
ie 'use' hooks can only be called synchronously within the 'component$'
function or another 'use' method.
For more information see: https://qwik.builder.io/docs/components/tasks/#use-

Esto es debido a que los métodos use*() proporcionan hooks al estado y ciclo de vida de component$, es decir, los hooks solo se pueden llamar de forma síncrona dentro de la función component$ o en otro método use

Puede llamar a otros hooks

No es una regla, pero es algo que tenemos que tener en cuenta de manera particular en los custom hooks de Qwik (como en React) en el que pueden llamar a otros hooks.

En este caso, Qwik considerará como custom hook a aquella función en la que dentro de ella llama a un hook original o a otro custom hook que hemos creado.

Teniendo en cuenta estos aspectos, os muestro a continuación lo que hay que tener en cuenta para aplicar bien el uso de los hooks tanto los que vienen de serie (useSignal, useStore,…), como los custom hooks.

Cómo usar un hook correctamente

A continuación, os dejo la formas incorrectas / correctas que tenemos para poder hacer uso de los hooks en Qwik.

useHook(); // <-- ❌ No funcionará por estar fuera de component$

export default component$(() => {
useCustomHook(); // <-- ✅ Dentro de component$ y en la raíz
if (condition) {
useHook(); // <-- ❌ Aunque esté dentro de component$, no está en la raíz
}
useTask$(() => {
useNavigate(); // <-- ❌ No podemos usar un hook dentro de otro
});
const myQrl = $(() => useHook()); // <-- ❌ Debe de estar en la raíz
return <button onClick$={() => useHook()}></button>; // <-- ❌ No se puede con acciones
});

// Dentro de una función denominada custom hook funciona como en component$
function useCustomHook() {
useHook(); // <-- ✅ Funciona por estar en raíz
if (condition) {
useHook(); // <-- ❌ No está en la raíz, está dentro de condición
}
}

Esta porción de código os recomiendo que la tengáis siempre a mano mientras estéis aprendiendo. Luego, cuando ya tengáis todo bien entendido, inconscientemente lo aplicaréis perfectamente sin pensar mucho.

Primer custom hook en Qwik: useCounter

A continuación, os voy a mostrar como podemos crear un custom hook paso a paso, desde el desarrollo de un componente, donde aplicaremos la lógica necesaria para darle funcionamiento.

Una vez comprobado que todo funciona perfecto, creamos el custom hook (no olvidéis respetad el uso de la palabra use*()) desacoplando ese código del componente principal para poder reutilizarlo en otros componentes tantas veces como queramos.

Paso 1: Crear la lógica de un contador

Escribiremos el siguiente código, donde implementamos un valor mediante un useSignal, para almacenar el estado de el.

Posteriormente, aplicamos ese valor en la parte del layout, para que se visualice junto dos botones de acción, para ir sumando +1 y el otro para hacer un reset del estado del contador y ponerlo a 0

import { component$, useSignal } from '@builder.io/qwik';

export default component$(() => {
const counter = useSignal(0);
return (
<>
<h4>Valor del contador : {counter.value}</h4>
<button onClick$={() => counter.value++}>+1</button>&nbsp;
<button onClick$={() => (counter.value = 0)}>Reset</button>
</>
);
});

Esto se verá de la siguiente forma (tres veces click +1):

Podéis probar la lógica, funciona sin problemas.

Ahora bien, queremos que esa lógica, la de tener el valor del contador, y las funciones que corresponden a +1 y el reset, las queremos quitar del componente.

Paso 2: Crear hook useCounter

Teniendo la lógica implementada en el componente, necesitamos los tres elementos principales, creando un custom hook(en src/hooks llamando como useCounter.tsx) siguiendo lo mencionado anteriormente:

import { useSignal, $ } from '@builder.io/qwik';

const useCounter = (initialValue = 0) => {
// 1
const counter = useSignal(initialValue);

// 2
const increment = $(() => counter.value++);
const reset = $(() => (counter.value = 0));

// 3
return {
counter,
increment,
reset,
};
};

export default useCounter;

Como podemos ver en las líneas de código anteriores, nuestra función se llama useCounter, siguiendo la primera regla de los custom hooks.

Y dentro de el, estamos aplicando lo siguiente:

  1. Declarando un estado usando el hook useSignal para almacenar el valor de contador. Con esto estaremos llamando a otro hook desde nuestro nuevo hook.
  2. Crear las funciones serializadas (con $, muy importante para serializar) para incrementar y resetear el contador.
  3. Devolvemos tanto el estado como las funciones, para poder usarlas en los componentes que queramos

Y ahora usando el custom hook dentro del componente, lo dejamos de la siguiente forma:

import { component$ } from '@builder.io/qwik';
// Importamos el custom hook
import useCounter from '~/hooks/useCounter';

export default component$(() => {
// Iniciamos el custom hook y obtenemos el valor de estado y las funciones
const { counter, increment, reset } = useCounter();
return (
<>
<h4>Valor del contador : {counter.value}</h4>
<button onClick$={increment}>+1</button>&nbsp;
<button onClick$={reset}>Reset</button>
</>
);
});

Si guardamos los cambios, seguiremos con la misma apariencia del contador y seguirá funcionando de la misma forma, solo que ahora en vez de tener la lógica dentro del componente, la tendremos fuera, con lo que nos dará más libertad para usarlo en otros componentes (quitando la duplicidad de códigos repetitivos) y en el caso de realizar cambios, que todos estos reciban dichos cambios en el momento.

En resumen, podemos afirmar que los custom hooks en Qwik (y React) son muy útiles para extraer funcionalidades, hacer refactorizaciones de código y mantener nuestros componentes más simplificados.

Ahora que ya sabemos como trabajar en el desarrollo de un custom hook, a continuación os voy a mostrar varios ejemplos en diferentes variantes haciendo distintas utilidades como puede ser un selector de temas (dark / light) y un hook que detecta la posición de nuestro ratón en la ventana activa del navegador.

Custom Hook: useTheme

Este custom hook lo que va a hacer es que mediante una opción de tipo toggle es que podamos seleccionar la apariencia de nuestra plantilla de clara a oscura y viceversa, con las variantes light y dark.

Creamos el hook en src/hooks con el nombre useTheme.tsx y añadimos el siguiente código:

import { useSignal, $, useStylesScoped$ } from '@builder.io/qwik';

const useTheme = () => {
// 1
const theme = useSignal('dark');

// 2
useStylesScoped$(`
.dark {
background: #1d2033;
color: white;
}
.light {
background: white;
color: black;
}

.light, .dark {
padding: 1rem;
}
`);

// 3
const toggleTheme = $(() => {
theme.value = theme.value === 'light' ? 'dark' : 'light';
});

// 4
return {
theme,
toggleTheme,
};
};

export default useTheme;

Y en este código los aspectos a tener en cuenta son los siguientes:

  1. Crear estado mediante useSignal para ir almacenando la variante del theme con el que estamos trabajando, cuyo valor por defecto es dark.
  2. Uso de otro hook, en este caso estilos personalizados con useStylesScoped$() para que estos estilos estén acoplados a los componentes que hagan uso de este hook
  3. Función para seleccionar el theme entre dark y light
  4. Devolver el valor del theme y la función para hacer el cambio de variante.

Y ahora, añadiéndolo en un componente:

import { component$ } from '@builder.io/qwik';
import useTheme from '~/hooks/useTheme';

export default component$(() => {
const { theme, toggleTheme } = useTheme();

return (
<div class={theme.value}>
<h4>Hook useTheme</h4>
<p>Tema seleccionado: {theme.value}</p>
<button onClick$={toggleTheme}>Cambiar</button>
</div>
);
});

Cuya apariencia será la siguiente, que por defecto será la apariencia dark, la de tono más oscuro, que podremos cambiar con la opción Cambiar:

Cambiando a la apariencia clara, es decir a la variante light

Bien, ya tenemos otro custom hook, vamos a por el tercero y último.

Custom Hook: useMousePosition

Vamos a crear un hook, en el que ya estemos haciendo uso del hook useOnDocument, para poder obtener mediante un evento de movimiento del ratón, la posición actual dentro de nuestro documento web, lo que sería toda la ventana.

Creamos el hook en src/hooks con el nombre useMousePosition.tsx y añadimos el siguiente código:

import { useStore, $, useOnDocument } from '@builder.io/qwik';

const useMousePosition = () => {
// 1.- Guardamos la posición del cursor del ratón con sus coordenadas
const position = useStore({ x: 0, y: 0 });

// 2.- Escuchar eventos en el elemento raíz del componente actual.
useOnDocument(
'mousemove',
$((event) => {
// 3.- Obtenemos el evento del ratón
const { x, y } = event as MouseEvent;
// 4.- Actualizamos
position.x = x;
position.y = y;
})
);
return position;
};

export default useMousePosition;

Y una vez definido el custom hook, lo añadimos en el componente:

import { component$ } from '@builder.io/qwik';
import useMousePosition from '~/hooks/useMousePosition';

export default component$(() => {
// 1.- Uso de nuestro hook para detectar la posición del cursor
const pos = useMousePosition();
// 2.- Mostrar las coordenadas x, y
return (
<div>
MousePosition: ({pos.x}, {pos.y})
</div>
);
});

Y una vez cargado el componente, veremos como cambian los valores de x e y si movemos el cursor del ratón en lo que es el documento de nuestra página.

El resultado de los tres custom hooks que hemos trabajado, lo tenéis aquí a continuación con su código y podéis ver su funcionamiento.

Ideas de Custom Hooks

En este punto, no os enseñaré a crear más custom hooks, pero os voy a proporcionar algunos ejemplos de custom hooks que podríais crear con lo que hemos aprendido y siguiendo la información de la documentación oficial:

  • useLocalStorage: Almacena y recupera datos en el almacenamiento local del navegador utilizando la API localStorage.
  • useWindowWidth: Obtiene y actualiza el ancho de la ventana del navegador en tiempo real.
  • useDebounce: Agrega un retardo antes de ejecutar una función, útil para implementar búsqueda con retardo o evitar ejecuciones innecesarias.
  • usePrevious: Almacena el valor anterior de una variable o estado para realizar comparaciones o acciones basadas en cambios.
  • useClickOutside: Detecta y maneja los clics fuera de un elemento específico, útil para cerrar menús o modales al hacer clic fuera de ellos.
  • useHover: Detecta si el cursor está sobre un elemento, proporcionando un estado booleano para realizar acciones en función del estado de "hover".
  • useFetch: Realiza una solicitud de datos a una API o servidor y maneja el ciclo de vida de la solicitud, incluyendo estados de carga, éxito y error.
  • useKeyPress: Detecta la pulsación de una tecla específica o cualquier tecla del teclado y proporciona un estado booleano para realizar acciones en respuesta a la pulsación.
  • useToggle: Alternar entre dos estados booleanos (verdadero/falso) y proporciona una función para cambiar el estado actual (prácticamente sería similar al useTheme, pero en este caso devolviendo un valor booleano)
  • useGeolocation: Obtiene la ubicación actual del usuario a través del API de geolocalización del navegador.

Conclusion

Los custom hooks son una característica poderosa en Qwik (y React) que nos permitirán encapsular y reutilizar la lógica común en nuestros componentes. Al separar la lógica en hooks personalizados, podemos mantener nuestros componentes más limpios, centrados en la presentación y fáciles de entender. Esto mejora la reutilización del código, facilita el mantenimiento y agiliza el desarrollo de nuevas funcionalidades.

Los custom hooks nos van a brindar flexibilidad y versatilidad al permitirnos abordar una amplia gama de necesidades en nuestras aplicaciones, desde el manejo del estado y los efectos secundarios hasta la interacción con APIs externas. Al utilizar custom hooks, podemos compartir y aplicar fácilmente la misma lógica en múltiples componentes, evitando la duplicación de código y mejorando la eficiencia del desarrollo.

En definitiva, los custom hooks nos dan un poder y control muy grande como desarrolladores de Qwik al mejorar la modularidad, la legibilidad y la reutilización del código. Al utilizar esta técnica, podemos construir aplicaciones más eficientes y escalables, lo que nos permitirá enfrentarnos a los desafíos del desarrollo web con mayor confianza y agilidad.

Todos los artículos publicados del curso los encontraréis en la siguiente lista que iré actualizando semanalmente y estableciendo el orden natural recomendado:

Qwik paso a paso desde 0 al detalle

23 stories

Presencia en redes sociales

Podéis encontrarme en las siguientes redes.

--

--

Anartz Mugika Ledo🤗

[{#frontend:[#mobile:{#android, #kotlin, #ionic}}, {#web:{#angular, #qwik, #bootstrap}}],{#backend: [{#graphql, #nestjs,#express, #mongodb, #mysql}]}]