Mejora de la Experiencia del Usuario al Editar To Do's en React

Clase 24 de 30Curso de React.js: Navegación con React Router

Contenido del curso

Fake authentication con React Router DOM 6

React Router en TODO Machine

Resumen

Cuando trabajas con formularios de edición en React, uno de los detalles que más impacta la experiencia del usuario es mostrar el texto original que se va a editar. Si el usuario llega a un formulario vacío y debe reescribir todo desde cero, la experiencia se rompe. Aquí se aborda exactamente ese problema: cómo precargar valores por defecto en un textarea y cómo usar useLocation de React Router para transmitir datos entre rutas y evitar tiempos de carga innecesarios.

¿Cómo enviar un valor por defecto al formulario de edición?

El punto de partida es la página de edición de un todo. Al hacer clic en el botón de editar, se abre el formulario pero el textarea aparece vacío. Para solucionarlo, se necesita una propiedad que lleve el texto original al componente TodoForm.

Desde la ruta EditTodoPage se envía una nueva prop llamada defaultTodoText al componente del formulario. Pero para obtener ese texto, primero hay que buscar el todo correcto dentro de la lista usando su ID [01:19].

La solución consiste en crear una función getTodo dentro del custom hook useTodos [01:51]:

  • Recibe el ID del todo que se busca.
  • Filtra la lista de todos para encontrar la coincidencia.
  • Retorna el objeto completo del todo.

Un detalle interesante surge al decidir dónde ubicar esta función: no actualiza el estado, simplemente lo lee. No encaja del todo en state updaters ni es un estado puro, pero se retorna dentro del objeto state como una función de lectura [02:37].

¿Por qué el todo aparece como undefined y cómo se soluciona?

Al probar la implementación, getTodo devuelve undefined [03:34]. El problema no está en la lógica de búsqueda, sino en que el useLocalStorage simula un comportamiento asíncrono con un setTimeout [04:17]. Durante esos primeros segundos, la lista de todos es un array vacío, así que no hay nada que encontrar.

La solución es preguntar por el estado de carga antes de intentar buscar el todo:

  • Si loading es true, se muestra un mensaje de "cargando..." [05:09].
  • Si loading es false, ya existe la lista completa y se puede llamar a getTodo con el ID obtenido de useParams.

En el componente TodoForm, el useState que controla el textarea recibe como valor inicial props.defaultTodoText o, si no existe, un string vacío [06:16]. Esto garantiza que no se rompa nada cuando no hay texto por defecto.

jsx const [value, setValue] = React.useState(props.defaultTodoText || '');

¿Cómo usar useLocation para evitar cargas innecesarias?

Aunque el formulario ya muestra el texto correcto, hay un problema de rendimiento: si el usuario ya ve la información en el home y navega al edit, vuelve a cargar todo desde cero [07:20]. Tres segundos de espera para datos que ya estaban disponibles.

Aquí entra useLocation, un custom hook de React Router DOM v6 que permite transmitir información entre rutas durante la navegación [07:40].

Desde el home, la función navigate recibe un segundo argumento con un objeto state:

jsx navigate(/edit/${todo.id}, { state: { todo: todo } });

En la página de edición, se recupera esa información con useLocation [09:01]:

jsx const location = useLocation();

La lógica condicional queda así:

  • Si location?.state?.todo existe, se usa directamente su texto. Sin esperas [09:30].
  • Si no existe (porque el usuario entró directamente por URL) y loading es true, se muestra el mensaje de carga.
  • Si no hay datos de location y ya terminó de cargar, se obtiene el texto con getTodo.

El operador de encadenamiento opcional (?.) es fundamental aquí [11:04]. Sin él, al recargar la página, state sería undefined y provocaría un error al intentar acceder a .todo.

¿Cuál es el resultado final de esta optimización?

  • Navegación desde el home: el texto aparece instantáneamente sin pantalla de carga.
  • Acceso directo por URL: se muestra "cargando" y, al terminar, aparece el texto correcto.
  • La edición funciona en ambos escenarios sin duplicar código [12:15].

Este patrón es especialmente útil cuando se trabaja con API REST reales, donde los tiempos de respuesta pueden ser significativos. Transmitir datos ya cargados entre rutas mejora notablemente la percepción de velocidad.

¿Encontraste una forma diferente de organizar getTodo dentro del custom hook? Comparte tu enfoque en los comentarios.