Cuando la lógica de persistencia y la lógica de estado conviven en un mismo componente, el código se vuelve difícil de mantener. La solución que propone React es poderosa y elegante: crear un custom React Hook que encapsule todo el trabajo con localStorage, dejando los componentes limpios y enfocados en su responsabilidad principal.
¿Por qué separar la lógica de localStorage en un custom hook?
El archivo app.js originalmente contenía dos responsabilidades mezcladas: el manejo del estado de la aplicación y la persistencia de datos en localStorage [01:00]. Cada vez que se necesitaba leer o guardar información, el componente acumulaba más líneas que no tenían relación directa con la interfaz de usuario.
Un custom React Hook permite abstraer esa lógica. Abstraer significa extraer un bloque de código hacia una función independiente para que el componente que lo consume no necesite conocer los detalles internos. En este caso, el hook se llama useLocalStorage y se encarga de:
- Leer un elemento de localStorage al iniciar.
- Parsear su contenido o establecer un valor inicial por defecto.
- Proveer un método para actualizar tanto el estado de React como localStorage simultáneamente.
¿Cuál es la regla principal para nombrar un custom hook?
React permite crear cualquier hook personalizado con total libertad, pero existe una regla fundamental: el nombre debe comenzar con la palabra use [02:27]. Puede ser usePatito, useUnicornio o useTodos; lo importante es respetar esa convención. Esto le indica a React que esa función sigue las reglas de los hooks y puede utilizar internamente otros hooks oficiales como React.useState.
¿Cómo se estructura useLocalStorage paso a paso?
El hook recibe dos parámetros [03:45]:
- itemName: el nombre con el que se guardará el elemento en localStorage (por ejemplo,
'todos_v1').
- initialValue: el valor inicial que se usará si no existe nada guardado previamente.
javascript
function useLocalStorage(itemName, initialValue) {
const localStorageItem = localStorage.getItem(itemName);
let parsedItem;
if (!localStorageItem) {
localStorage.setItem(itemName, JSON.stringify(initialValue));
parsedItem = initialValue;
} else {
parsedItem = JSON.parse(localStorageItem);
}
const [item, setItem] = React.useState(parsedItem);
const saveItem = (newItem) => {
localStorage.setItem(itemName, JSON.stringify(newItem));
setItem(newItem);
};
return [item, saveItem];
}
Dentro del hook se llama a React.useState [05:48], lo cual es completamente válido. Los custom hooks pueden consumir cualquier hook oficial de React. Esto permite que el estado interno del hook provoque re-renderizados en los componentes que lo utilicen, exactamente igual que si se llamara a useState directamente en el componente.
¿Cómo se consume useLocalStorage en un componente?
El componente App queda mucho más limpio. En lugar de manejar localStorage directamente, simplemente llama al hook [03:10]:
javascript
const [todos, saveTodos] = useLocalStorage('todos_v1', []);
El hook retorna un array con dos elementos: el estado actual y la función para actualizarlo. Este patrón es idéntico al que usa React.useState, lo que hace que la transición sea natural.
¿Por qué recibir initialValue como parámetro?
No todos los datos que se guardan en localStorage son arrays [06:30]. Si alguien quisiera guardar un nombre, el valor inicial debería ser un string vacío o un valor por defecto como 'Fernando'. Al parametrizar el initialValue, el hook se vuelve reutilizable para cualquier tipo de dato:
- Arrays de tareas:
useLocalStorage('todos_v1', []).
- Un nombre de usuario:
useLocalStorage('nombre_v1', 'Fernando').
- Cualquier estructura que se necesite persistir.
¿Se puede usar el mismo hook para múltiples elementos?
Absolutamente. En la demostración se creó un segundo uso del hook para guardar un elemento llamado patito_v1 con el valor 'Fernando' [08:50]:
javascript
const [patito, savePatito] = useLocalStorage('patito_v1', 'Fernando');
Al revisar localStorage en el navegador, aparecen ambos elementos guardados de forma independiente: los todos y el patito. Esto confirma que el hook es genérico y reutilizable, sin estar atado a una estructura de datos específica.
El resultado final es un componente app.js enfocado exclusivamente en la lógica de presentación, mientras que toda la complejidad de leer, parsear y guardar datos queda oculta dentro de useLocalStorage. Si trabajas en equipo, basta con decir: "usa este hook, recibe el estado y actualízalo; la persistencia ya está resuelta".
¿Has creado tus propios custom hooks? Comparte en los comentarios qué lógica has abstraído y cómo te ha simplificado el código.