Manejo de Eventos y Corrección de Errores en Aplicaciones React

Clase 24 de 27Curso de SolidJS

Contenido del curso

Resumen

Diseñar componentes que se comuniquen correctamente con su padre es una de las decisiones arquitectónicas más importantes en cualquier aplicación React. Cuando un componente hijo intenta acceder a una función que no existe en su propio contexto, la solución más limpia pasa por crear eventos personalizados mediante props y delegar la lógica de estado al componente que realmente lo posee.

¿Por qué delegar el cambio de estado al componente padre?

Cuando modificamos un todo a través de un setter, en realidad estamos alterando el estado general de la aplicación [01:02]. Ese estado no pertenece al componente hijo, sino al padre. Enviar la función directamente como prop funcionaría, pero existe un patrón de diseño más expresivo: definir eventos personalizados con el prefijo on.

Este prefijo es un estándar que ya conocemos de eventos nativos como onChange, onDoubleClick, onBlur y onClick [01:25]. Frameworks y librerías de componentes como Bootstrap o Material UI adoptan esta misma convención para sus eventos personalizados, lo que facilita la lectura del código y la colaboración entre equipos.

¿Cómo se crean eventos personalizados con props?

La mecánica es directa: se define una prop cuyo nombre empieza con on y cuyo valor es una función que el padre controla.

¿Cómo funciona onInputChange para el checkbox?

En el componente padre (App.jsx), al renderizar cada todo, se pasa una prop llamada onInputChange [02:25]. Dentro de esa función se ejecuta setTodos con la lógica necesaria para cambiar el estado del checkbox. En el componente hijo, el onChange del input simplemente dispara onInputChange:

jsx // Componente hijo <input type="checkbox" onChange={onInputChange} />

De esta forma, el hijo no conoce los detalles de implementación del estado; solo avisa que algo cambió.

¿Qué hace el evento onTextChanged al editar un elemento?

Cuando el usuario modifica el texto de un todo, se necesita un evento distinto: onTextChanged [03:22]. Este evento es especial porque requiere recibir el texto interno del componente hijo para actualizar la lista:

jsx // En App.jsx onTextChanged={(text) => { setTodos(produce(draft => { draft[index].text = text; })); }}

Dentro del componente hijo, el evento onBlur cumple dos funciones [04:28]:

  • Quitar el estado de content editable.
  • Ejecutar onTextChanged con el texto actualizado.

Esta composición mediante funciones demuestra el poder de la programación funcional: cada pieza hace una sola cosa y se combina de forma predecible.

¿Cómo se implementa onRemove para eliminar un todo?

Eliminar un elemento también corresponde al padre, que posee el arreglo completo [04:50]. Se crea el evento onRemove y se le pasa el índice actual:

jsx // En App.jsx onRemove={() => removeTodo(index)}

La función removeTodo, creada en clases anteriores, ejecuta un splice sobre la lista. En el componente hijo, el botón de eliminar simplemente llama a props.onRemove() en lugar de intentar acceder a una función inexistente.

¿Qué resultado se obtiene con este patrón de eventos?

Después de aplicar los tres eventos — onInputChange, onTextChanged y onRemove — la aplicación funciona sin errores en consola [05:20]:

  • Agregar elementos opera correctamente.
  • Eliminar un elemento responde al instante.
  • Cambiar el estado de completed actualiza la propiedad derivada calculada con useMemo.
  • Editar texto activa el content editable con onClick y guarda el cambio con onBlur.

El código queda limpio y desacoplado: el componente hijo solo se encarga de la presentación y de notificar eventos, mientras el padre gestiona todo el estado. Este patrón escala bien cuando la aplicación crece y facilita la reutilización de componentes.

Un detalle importante es que el estado modificado durante la sesión —dark mode, elementos completados o nuevos todosno persiste tras refrescar el navegador [05:55]. Implementar local storage para almacenar estos datos es el siguiente paso natural.

¿Has aplicado este patrón de eventos personalizados en tus proyectos? Comparte cómo organizas la comunicación entre componentes.