23.1. Pasando funciones entre componente por los props
Te explico cómo pasar datos del hijo al padre en React. Hay varias formas, pero la más común es mediante funciones callback.
1. Método Básico: Callback Function
Padre Component
jsx
import React, { useState } from 'react';
import Hijo from './Hijo';
function Padre() {
const [datoDelHijo, setDatoDelHijo] = useState('');
// Función que recibe datos del hijo
const manejarDatoDelHijo = (dato) => {
setDatoDelHijo(dato);
console.log('Dato recibido del hijo:', dato);
};
return (
<div>
<h1>Padre</h1>
<p>Dato del hijo: {datoDelHijo}</p>
{/* Paso la función como prop al hijo */}
<Hijo enviarDatoAlPadre={manejarDatoDelHijo} />
</div>
);
}
Hijo Component
jsx
import React, { useState } from 'react';
function Hijo({ enviarDatoAlPadre }) {
const [inputValue, setInputValue] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
// Llamo a la función del padre con los datos
enviarDatoAlPadre(inputValue);
setInputValue('');
};
return (
<div>
<h2>Hijo</h2>
<form onSubmit={handleSubmit}>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Escribe algo"
/>
<button type="submit">Enviar al padre</button>
</form>
</div>
);
}
2. Ejemplo Práctico Completo
Aquí te muestro un ejemplo más realista:
// App.js (Padre)
function App() {
const [listaTareas, setListaTareas] = useState([]);
const agregarTarea = (nuevaTarea) => {
setListaTareas([...listaTareas, {
id: Date.now(),
texto: nuevaTarea,
completada: false
}]);
};
return (
<div className="App">
<h1>Lista de Tareas</h1>
<FormularioTarea onAgregarTarea={agregarTarea} />
<ListaTareas tareas={listaTareas} />
</div>
);
}
// FormularioTarea.js (Hijo)
function FormularioTarea({ onAgregarTarea }) {
const [tarea, setTarea] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (tarea.trim()) {
onAgregarTarea(tarea); // ← Paso datos al padre
setTarea('');
}
};
return (
<form onSubmit={handleSubmit}>
<input
value={tarea}
onChange={(e) => setTarea(e.target.value)}
placeholder="Nueva tarea"
/>
<button type="submit">Agregar</button> </form>);}
3. Paso de Múltiples Datos
jsx
// Hijo
function FormularioUsuario({ onSubmit }) {
const [usuario, setUsuario] = useState({
nombre: '',
email: '',
edad: ''
});
const handleSubmit = (e) => {
e.preventDefault();
// Paso un objeto con múltiples datos
onSubmit(usuario);
};
return (
<form onSubmit={handleSubmit}>
<input
value={usuario.nombre}
onChange={(e) => setUsuario({...usuario, nombre: e.target.value})}
/>
{/* ... otros campos */}
</form>
);
}
// Padre
function App() {
const manejarNuevoUsuario = (usuarioData) => {
console.log('Usuario recibido:', usuarioData);
// nombre, email, edad disponibles aquí
};
return <FormularioUsuario onSubmit={manejarNuevoUsuario} />;
}
4. Patrones Avanzados
a) Usando Context API (para evitar prop drilling)
jsx
// Crear contexto
const DataContext = React.createContext();
// Proveedor en el padre
function Padre() {
const [data, setData] = useState(null);
return (
<DataContext.Provider value={{ data, setData }}>
<Hijo />
</DataContext.Provider>
);
}
// Hijo consume y actualiza
function Hijo() {
const { setData } = useContext(DataContext);
const enviarDato = () => {
setData('Dato del hijo');
};
return <button onClick={enviarDato}>Enviar</button>;
}
b) Usando useImperativeHandle (menos común)
jsx
// Hijo con forwardRef
const Hijo = forwardRef((props, ref) => {
const [dato, setDato] = useState('');
useImperativeHandle(ref, () => ({
getDato: () => dato
}));
return <input value={dato} onChange={e => setDato(e.target.value)} />;
});
// Padre
function Padre() {
const hijoRef = useRef();
const obtenerDato = () => {
const dato = hijoRef.current.getDato();
console.log(dato);
};
return (
<>
<Hijo ref={hijoRef} />
<button onClick={obtenerDato}>Obtener dato</button>
</>
);
}
5. Buenas Prácticas
Nombres descriptivos: Usa nombres como onSubmit, onSave, onUpdate
Props de sólo lectura: El hijo no debería modificar props directamente
Validación de props: Usa PropTypes o TypeScript
Lifting state up: Si varios hijos necesitan compartir estado, súbelo al ancestro común más cercano
Resumen
La forma más común y recomendada es:
Padre: Define una función que maneje los datos
Padre: Pasa esa función como prop al hijo
Hijo: Llama a la función prop con los datos como argumento
Padre: Recibe y procesa los datos
Este patrón mantiene un flujo de datos unidireccional y predecible, que es una de las fortalezas de React.
explicamelo de manera mas sencilla ,creo de de pasar una funcion del padre al hijo para que el hijo le mande los datos
¡Perfecto! Te lo explico de forma muy simple, como una llamada telefónica:
📞 Analogía Sencilla
Padre → Le da al hijo un teléfono (función)
Hijo → Llama por ese teléfono y le dice algo (datos)
Padre → Escucha lo que el hijo le dijo
🎯 Ejemplo Super Simple
Paso 1: El Padre prepara el "teléfono"
function Padre() {
// Esta función es el "teléfono"
const recibirMensaje = (mensaje) => {
alert("Mi hijo me dijo: " + mensaje);
};
return (
<div>
<h1>Yo soy el Papá</h1>
{/* Le paso el teléfono a mi hijo */}
<Hijo miTelefono={recibirMensaje} />
</div>
);
}
Paso 2: El Hijo usa el "teléfono"
javascript
function Hijo({ miTelefono }) {
return (
<div>
<h2>Yo soy el Hijo</h2>
<button onClick={() => miTelefono("¡Hola Papá!")}>
Llamar a Papá
</button>
</div>
);}
📝 Ejemplo Práctico con Formulario
Padre Component:
function Padre() {
// 1. Papá prepara su bolsillo para guardar cosas
const [cosasDelHijo, setCosasDelHijo] = useState([]);
// 2. Papá prepara su "mano extendida" para recibir
const recibirRegalo = (regalo) => {
console.log("Recibí:", regalo);
setCosasDelHijo([...cosasDelHijo, regalo]);
};
return (
<div>
<h1>Cosas que me dio mi hijo:</h1>
<ul>
{cosasDelHijo.map((cosa, index) => (
<li key={index}>{cosa}</li>
))}
</ul>
{/* 3. Papá le da su "mano extendida" al hijo */}
<Hijo manoParaRecibir={recibirRegalo} />
</div>
);}
Hijo Component:
javascript
function Hijo({ manoParaRecibir }) {
const [miRegalo, setMiRegalo] = useState("");
const darRegalo = () => {
// 4. Hijo pone algo en la mano del papá
manoParaRecibir(miRegalo);
setMiRegalo(""); // Vacío la caja
};
return (
<div>
<h2>Yo elijo un regalo para papá:</h2>
<input
value={miRegalo}
onChange={(e) => setMiRegalo(e.target.value)}
placeholder="Escribe un regalo"
/>
{/* 5. Hijo entrega el regalo */}
<button onClick={darRegalo}>
Dar regalo a Papá
</button>
</div>
);
}
🎮 Ejemplo Interactivo - Videojuego
javascript
// PADRE - Tiene el marcador
function Juego() {
const [puntos, setPuntos] = useState(0);
// Función para sumar puntos
const sumarPuntos = (cantidad) => {
setPuntos(puntos + cantidad);
console.log("¡Gané " + cantidad + " puntos!");
};
return (
<div>
<h1>PUNTOS TOTALES: {puntos}</h1>
{/* Le paso la función al jugador */}
<Jugador cuandoAnota={sumarPuntos} />
</div>
);
}
// HIJO - Es el jugador
function Jugador({ cuandoAnota }) {
const anotar = () => {
// Cada vez que anoto, le aviso al padre
cuandoAnota(10); // Le digo: "sumá 10 puntos"
};
return (
<div>
<h2>Jugador</h2>
<button onClick={anotar}>
¡ANOTAR CANASTA! 🏀
</button>
</div>
);
}
🍕 Ejemplo de la Vida Real: Pedir Pizza
javascript
// PADRE - Quien paga
function Papa() {
const [pedido, setPedido] = useState("");
// Función para recibir el pedido
const recibirPedido = (pizza) => {
setPedido(pizza);
console.log("Voy a pedir: " + pizza);
};
return (
<div>
<h1>Papá - Voy a pedir: {pedido}</h1>
{/* Le pregunto al hijo qué quiere */}
<Hijo decirmeQueQuiere={recibirPedido} />
</div>
);
}
// HIJO - Quien elige
function Hijo({ decirmeQueQuiere }) {
const elegirPizza = (sabor) => {
// Le digo a papá lo que quiero
decirmeQueQuiere("Pizza de " + sabor);
};
return (
<div>
<h2>Hijo - ¿Qué quiero comer?</h2>
<button onClick={() => elegirPizza("Muzzarella")}>
Muzzarella 🍕
</button>
<button onClick={() => elegirPizza("Jamón")}>
Jamón 🍖
</button>
</div>
);
}
✨ En Resumen:
Padre crea una función como function recibir(datos) { ... }
Padre la pasa como prop al hijo: <Hijo enviar={recibir} />
Hijo recibe la función como prop: function Hijo({ enviar }) { ... }
Hijo la llama con datos: enviar("mis datos")
Padre recibe los datos y hace lo que quiera con ellos
¡Es como darle a tu hijo un walkie-talkie para que te hable! 🎤
El hijo no modifica directamente las cosas del padre, sólo le habla a través de la función que el padre le prestó
**********************************************************************
Comunicación de Props de Hijo a Padre en React
En React, el flujo de datos principal es unidireccional: del padre al hijo. Para comunicar datos del hijo al padre, se utiliza una técnica donde el padre pasa una función como prop al hijo, y el hijo llama a esa función cuando necesita enviar datos hacia arriba.
Ejemplo Básico
jsx
// Componente Padre
function Padre() {
// Función que recibirá datos del hijo
const recibirDatosDelHijo = (datos) => {
console.log("Datos recibidos del hijo:", datos);
// Aquí puedes actualizar el estado del padre con los datos
};
return (
<div>
<h1>Componente Padre</h1>
{/* Pasamos la función como prop al hijo */}
<Hijo onEnviarDatos={recibirDatosDelHijo} />
</div>
);
}
// Componente Hijo
function Hijo({ onEnviarDatos }) {
const manejarClick = () => {
const datos = { mensaje: "Hola desde el hijo", fecha: new Date() };
// Llamamos a la función que recibimos como prop
onEnviarDatos(datos);
};
return (
<div>
<h2>Componente Hijo</h2>
<button onClick={manejarClick}>Enviar datos al padre</button>
</div>
);
}
Ejemplo con Formularios (Método Recomendado)
Esta técnica es especialmente útil para formularios controlados:
jsx
import { useState } from 'react';
// Componente Padre
function FormularioPadre() {
const [datosFormulario, setDatosFormulario] = useState({
nombre: '',
email: '',
edad: ''
});
// Función para actualizar el estado cuando el hijo envíe datos
const manejarDatosDelHijo = (datos) => {
setDatosFormulario(datos);
console.log("Formulario actualizado:", datos);
};
const manejarSubmit = (e) => {
e.preventDefault();
console.log("Enviando datos finales:", datosFormulario);
// Aquí normalmente enviarías los datos a un servidor
};
return (
<div>
<h1>Formulario Controlado</h1>
<form onSubmit={manejarSubmit}>
{/* Pasamos la función al componente hijo */}
<FormularioHijo
datos={datosFormulario}
onCambio={manejarDatosDelHijo}
/>
<button type="submit">Enviar</button>
</form>
<div>
<h3>Vista previa de datos:</h3>
<p>Nombre: {datosFormulario.nombre}</p>
<p>Email: {datosFormulario.email}</p>
<p>Edad: {datosFormulario.edad}</p>
</div>
</div>
);
}
// Componente Hijo (Formulario)
function FormularioHijo({ datos, onCambio }) {
// Función local para manejar cambios en los inputs
const manejarCambio = (e) => {
const { name, value } = e.target;
// Creamos una copia actualizada de los datos
const nuevosDatos = {
...datos,
[name]: value
};
// Enviamos los datos actualizados al padre
onCambio(nuevosDatos);
};
return (
<div>
<div>
<label>Nombre:</label>
<input
type="text"
name="nombre"
value={datos.nombre}
onChange={manejarCambio}
/>
</div>
<div>
<label>Email:</label>
<input
type="email"
name="email"
value={datos.email}
onChange={manejarCambio}
/>
</div>
<div>
<label>Edad:</label>
<input
type="number"
name="edad"
value={datos.edad}
onChange={manejarCambio}
/>
</div>
</div>
);
}
Ejemplo con Múltiples Hijos
jsx
// Componente Padre
function Aplicacion() {
const [tareas, setTareas] = useState([
{ id: 1, texto: 'Aprender React', completada: false },
{ id: 2, texto: 'Practicar props', completada: true }
]);
// El hijo llamará a esta función para agregar una tarea
const agregarTarea = (textoTarea) => {
const nuevaTarea = {
id: Date.now(),
texto: textoTarea,
completada: false
};
setTareas([...tareas, nuevaTarea]);
};
// El hijo llamará a esta función para eliminar una tarea
const eliminarTarea = (id) => {
setTareas(tareas.filter(tarea => tarea.id !== id));
};
return (
<div>
<h1>Lista de Tareas</h1>
{/* Componente para agregar tareas */}
<AgregarTareaForm onAgregarTarea={agregarTarea} />
{/* Componente para mostrar tareas */}
<ListaTareas
tareas={tareas}
onEliminarTarea={eliminarTarea}
/>
<p>Total de tareas: {tareas.length}</p>
</div>
);
}
// Componente Hijo 1: Formulario para agregar
function AgregarTareaForm({ onAgregarTarea }) {
const [input, setInput] = useState('');
const manejarSubmit = (e) => {
e.preventDefault();
if (input.trim()) {
// Llamamos a la función del padre
onAgregarTarea(input);
setInput('');
}
};
return (
<form onSubmit={manejarSubmit}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Nueva tarea..."
/>
<button type="submit">Agregar</button>
</form>
);
}
// Componente Hijo 2: Lista de tareas
function ListaTareas({ tareas, onEliminarTarea }) {
return (
<ul>
{tareas.map(tarea => (
<li key={tarea.id}>
{tarea.texto}
<button onClick={() => onEliminarTarea(tarea.id)}>
Eliminar
</button>
</li>
))}
</ul>
);
}
Patrón "Lifting State Up" (Elevar el Estado)
Esta técnica de pasar funciones como props está relacionada con el patrón "Lifting State Up":
jsx
// El estado se mantiene en el componente más alto que lo necesita
function App() {
const [temperatura, setTemperatura] = useState('');
const manejarCambio = (valor) => {
setTemperatura(valor);
};
return (
<div>
<EntradaTemperatura
temperatura={temperatura}
onCambioTemperatura={manejarCambio}
/>
<ResultadoTemperatura temperatura={temperatura} />
</div>
);
}
// Componente controlado que recibe valor y función de cambio
function EntradaTemperatura({ temperatura, onCambioTemperatura }) {
return (
<fieldset>
<legend>Ingresa la temperatura:</legend>
<input
type="number"
value={temperatura}
onChange={(e) => onCambioTemperatura(e.target.value)}
/>
</fieldset>
);
}
// Otro componente que también usa el mismo estado
function ResultadoTemperatura({ temperatura }) {
return (
<div>
{temperatura && (
<p>
{temperatura}°C son {temperatura * 9/5 + 32}°F
</p>
)}
</div>
);
}
Resumen
Flujo de datos: React tiene flujo unidireccional (padre → hijo).
Comunicación hijo → padre: Se pasa una función como prop del padre al hijo.
El hijo llama la función con los datos que quiere enviar.
El padre actualiza su estado con esos datos.
Para formularios: Este es el método recomendado para crear componentes controlados.
Ventajas:
Mantiene el estado centralizado
Fácil depuración
Flujo de datos predecible
Reutilización de componentes
Esta técnica es fundamental en React y se usa constantemente en aplicaciones reales para mantener la sincronización entre componentes.
****************************************
Pasar propiedades de hijo a padre en React
En React, el flujo de datos es unidireccional: de padre a hijo. Para pasar datos del hijo al padre, se usa una técnica llamada "lifting state up" (elevar el estado) o pasar callbacks como props.
Concepto básico
El padre pasa una función como prop al hijo, y el hijo llama a esa función con los datos que quiere enviar al padre.
Ejemplo 1: Contador simple
jsx
// Componente Padre
import React, { useState } from 'react';
import Hijo from './Hijo';
function Padre() {
const [valorDesdeHijo, setValorDesdeHijo] = useState('');
// Función que recibirá datos del hijo
const manejarDatosDelHijo = (datos) => {
setValorDesdeHijo(datos);
};
return (
<div style={{ padding: '20px', border: '2px solid blue' }}>
<h2>Componente Padre</h2>
<p>Valor recibido del hijo: <strong>{valorDesdeHijo}</strong></p>
{/* Pasamos la función como prop al hijo */}
<Hijo onEnviarDatos={manejarDatosDelHijo} />
</div>
);
}
export default Padre;
jsx
// Componente Hijo
import React, { useState } from 'react';
function Hijo({ onEnviarDatos }) {
const [inputValue, setInputValue] = useState('');
const manejarCambio = (e) => {
setInputValue(e.target.value);
};
const manejarEnvio = () => {
// Llamamos a la función del padre con los datos
onEnviarDatos(inputValue);
setInputValue('');
};
return (
<div style={{ padding: '15px', border: '1px solid green', marginTop: '10px' }}>
<h3>Componente Hijo</h3>
<input
type="text"
value={inputValue}
onChange={manejarCambio}
placeholder="Escribe algo..."
/>
<button onClick={manejarEnvio}>Enviar al padre</button>
</div>
);
}
export default Hijo;
Ejemplo 2: Formulario de tareas
jsx
// Componente Padre - Lista de tareas
import React, { useState } from 'react';
import FormularioTarea from './FormularioTarea';
function ListaTareas() {
const [tareas, setTareas] = useState([]);
// Función para agregar nueva tarea desde el hijo
const agregarTarea = (nuevaTarea) => {
setTareas([...tareas, {
id: Date.now(),
texto: nuevaTarea,
completada: false
}]);
};
return (
<div style={{ padding: '20px', maxWidth: '500px' }}>
<h1>Lista de Tareas</h1>
{/* Pasamos la función para agregar tareas */}
<FormularioTarea onAgregarTarea={agregarTarea} />
<h3>Tareas:</h3>
<ul>
{tareas.map(tarea => (
<li key={tarea.id}>
{tarea.texto}
{tarea.completada && ' ✓'}
</li>
))}
</ul>
</div>
);
}
export default ListaTareas;
jsx
// Componente Hijo - Formulario de tarea
import React, { useState } from 'react';
function FormularioTarea({ onAgregarTarea }) {
const [textoTarea, setTextoTarea] = useState('');
const manejarSubmit = (e) => {
e.preventDefault();
if (textoTarea.trim() === '') return;
// Enviamos la nueva tarea al padre
onAgregarTarea(textoTarea);
setTextoTarea('');
};
return (
<form onSubmit={manejarSubmit} style={{ marginBottom: '20px' }}>
<input
type="text"
value={textoTarea}
onChange={(e) => setTextoTarea(e.target.value)}
placeholder="Nueva tarea..."
style={{ padding: '8px', marginRight: '10px' }}
/>
<button type="submit">Agregar Tarea</button>
</form>
);
}
export default FormularioTarea;
Ejemplo 3: Componente de calificación
jsx
// Componente Padre - Aplicación de reseñas
import React, { useState } from 'react';
import SelectorCalificacion from './SelectorCalificacion';
function AppReseñas() {
const [calificacion, setCalificacion] = useState(0);
const [reseñas, setReseñas] = useState([]);
// Función para manejar la calificación del hijo
const manejarCalificacion = (valor, comentario) => {
setCalificacion(valor);
// Agregar a la lista de reseñas
setReseñas([
...reseñas,
{ valor, comentario, fecha: new Date().toLocaleDateString() }
]);
};
return (
<div style={{ padding: '20px', fontFamily: 'Arial' }}>
<h1>Sistema de Reseñas</h1>
<p>Calificación actual: {calificacion}/5</p>
{/* Pasamos la función al hijo */}
<SelectorCalificacion onCalificar={manejarCalificacion} />
<h3>Reseñas anteriores:</h3>
{reseñas.length === 0 ? (
<p>No hay reseñas aún</p>
) : (
<ul>
{reseñas.map((reseña, index) => (
<li key={index}>
<strong>{reseña.valor}/5</strong> - {reseña.comentario}
<span style={{ color: 'gray', fontSize: '0.8em', marginLeft: '10px' }}>
({reseña.fecha})
</span>
</li>
))}
</ul>
)}
</div>
);
}
export default AppReseñas;
jsx
// Componente Hijo - Selector de calificación
import React, { useState } from 'react';
function SelectorCalificacion({ onCalificar }) {
const [calificacionSeleccionada, setCalificacionSeleccionada] = useState(0);
const [comentario, setComentario] = useState('');
const manejarClickEstrella = (valor) => {
setCalificacionSeleccionada(valor);
};
const manejarEnvio = () => {
if (calificacionSeleccionada === 0) {
alert('Por favor, selecciona una calificación');
return;
}
// Enviamos la calificación y comentario al padre
onCalificar(calificacionSeleccionada, comentario);
setComentario('');
};
return (
<div style={{ padding: '15px', border: '1px solid #ddd', borderRadius: '5px' }}>
<h3>Califica nuestro servicio:</h3>
<div style={{ marginBottom: '10px' }}>
{[1, 2, 3, 4, 5].map((estrella) => (
<button
key={estrella}
onClick={() => manejarClickEstrella(estrella)}
style={{
fontSize: '24px',
background: 'none',
border: 'none',
cursor: 'pointer',
color: estrella <= calificacionSeleccionada ? 'gold' : 'lightgray'
}}
>
{estrella <= calificacionSeleccionada ? '★' : '☆'}
</button>
))}
<span style={{ marginLeft: '10px' }}>{calificacionSeleccionada}/5</span>
</div>
<textarea
value={comentario}
onChange={(e) => setComentario(e.target.value)}
placeholder="Comentario opcional..."
style={{ width: '100%', padding: '8px', marginBottom: '10px' }}
/>
<button onClick={manejarEnvio} style={{ padding: '8px 16px' }}>
Enviar Calificación
</button>
</div>
);
}
export default SelectorCalificacion;
Resumen de la técnica
En el componente padre: Define una función que manejará los datos recibidos del hijo.
Pasa la función como prop al componente hijo.
En el componente hijo: Recibe la función como prop y la llama cuando necesite enviar datos al padre.
El hijo pasa los datos como argumento(s) de la función.
Ventajas de este patrón
Mantiene el flujo de datos predecible
Centraliza el estado en el componente padre
Facilita la comunicación entre componentes hermanos (a través del padre común)
Hace los componentes hijos más reutilizables
Este patrón es fundamental en React y se usa constantemente en aplicaciones reales
Comentarios
Publicar un comentario