9.5-Tutorial: Paso de Datos entre Componentes en React
Tutorial: Paso de Datos entre Componentes en React
馃摎 Conceptos B谩sicos
En React, los datos fluyen de dos formas:
Del Padre al Hijo: Usando props (propiedades)
Del Hijo al Padre: Usando funciones callback
馃幆 Parte 1: Del Padre al Hijo (Props)
Ejemplo B谩sico
jsx
// COMPONENTE PADRE
function Padre() {
const mensaje = "¡Hola desde el padre!";
return (
<div>
<h2>Componente Padre</h2>
{/* Paso de datos al hijo mediante props */}
<Hijo mensaje={mensaje} />
</div>
);
}
// COMPONENTE HIJO
function Hijo(props) {
return (
<div style={{ backgroundColor: '#f0f0f0', padding: '20px' }}>
<h3>Componente Hijo</h3>
{/* Accedemos al prop recibido */}
<p>Mensaje recibido: <strong>{props.mensaje}</strong></p>
</div>
);
}
Ejemplo con M煤ltiples Props
jsx
function App() {
const usuario = {
nombre: "Ana",
edad: 25,
ciudad: "Madrid"
};
return (
<div>
<h1>Aplicaci贸n Principal</h1>
{/* Pasamos m煤ltiples props */}
<TarjetaUsuario
nombre={usuario.nombre}
edad={usuario.edad}
ciudad={usuario.ciudad}
esActivo={true}
/>
</div>
);
}
function TarjetaUsuario({ nombre, edad, ciudad, esActivo }) {
// Desestructuraci贸n de props
return (
<div style={{
border: '2px solid #4CAF50',
borderRadius: '10px',
padding: '20px',
margin: '20px',
backgroundColor: esActivo ? '#e8f5e9' : '#f5f5f5'
}}>
<h3>Usuario: {nombre}</h3>
<p>Edad: {edad} a帽os</p>
<p>Ciudad: {ciudad}</p>
<p>Estado: {esActivo ? '✅ Activo' : '❌ Inactivo'}</p>
</div>
);
}
馃攧 Parte 2: Del Hijo al Padre (Funciones Callback)
⚡ EL CONCEPTO CLAVE
El padre le pasa al hijo una funci贸n, y el hijo la ejecuta con datos
jsx
// COMPONENTE PADRE
function Padre() {
const [mensajeRecibido, setMensajeRecibido] = useState("");
// ⭐ Funci贸n que recibe datos del hijo
const recibirDatosDelHijo = (datos) => {
setMensajeRecibido(datos);
console.log("Padre recibi贸:", datos);
};
return (
<div style={{ backgroundColor: '#e3f2fd', padding: '20px' }}>
<h2>馃彔 Componente Padre</h2>
<p>Mensaje del hijo: <strong>{mensajeRecibido}</strong></p>
{/* Paso la funci贸n al hijo como prop */}
<Hijo enviarAlPadre={recibirDatosDelHijo} />
</div>
);
}
// COMPONENTE HIJO
function Hijo({ enviarAlPadre }) {
const [inputValue, setInputValue] = useState("");
const manejarEnvio = () => {
if (inputValue.trim()) {
// ⭐ Ejecuto la funci贸n del padre con mis datos
enviarAlPadre(inputValue);
setInputValue("");
}
};
return (
<div style={{ backgroundColor: '#f3e5f5', padding: '20px', marginTop: '20px' }}>
<h3>馃懚 Componente Hijo</h3>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Escribe un mensaje para el padre"
style={{ padding: '10px', width: '300px' }}
/>
<button
onClick={manejarEnvio}
style={{ padding: '10px 20px', marginLeft: '10px' }}
>
Enviar al Padre 馃摛
</button>
</div>
);
}
馃幃 Ejemplo Interactivo: Contador Padre-Hijo
jsx
function ContadorApp() {
const [contadorPadre, setContadorPadre] = useState(0);
// Funci贸n que recibe datos del hijo
const actualizarContador = (nuevoValor) => {
setContadorPadre(nuevoValor);
};
return (
<div style={{ textAlign: 'center', padding: '40px' }}>
<h1>馃敘 CONTADOR PADRE-HIJO</h1>
<div style={{
backgroundColor: '#bbdefb',
padding: '30px',
borderRadius: '10px',
marginBottom: '30px'
}}>
<h2>Padre</h2>
<p style={{ fontSize: '48px', fontWeight: 'bold' }}>
{contadorPadre}
</p>
</div>
{/* Paso la funci贸n al hijo */}
<Botonera
enviarContador={actualizarContador}
contadorActual={contadorPadre}
/>
</div>
);
}
function Botonera({ enviarContador, contadorActual }) {
const incrementar = () => {
// Env铆o el nuevo valor al padre
enviarContador(contadorActual + 1);
};
const decrementar = () => {
enviarContador(contadorActual - 1);
};
const reiniciar = () => {
enviarContador(0);
};
return (
<div style={{
backgroundColor: '#fce4ec',
padding: '30px',
borderRadius: '10px'
}}>
<h3>Hijo: Botonera de Control</h3>
<div style={{ marginTop: '20px' }}>
<button
onClick={incrementar}
style={styles.boton}
>
➕ Incrementar
</button>
<button
onClick={decrementar}
style={styles.boton}
>
➖ Decrementar
</button>
<button
onClick={reiniciar}
style={{...styles.boton, backgroundColor: '#f44336'}}
>
馃攧 Reiniciar
</button>
</div>
<p style={{ marginTop: '20px' }}>
<small>El hijo controla el contador del padre</small>
</p>
</div>
);
}
const styles = {
boton: {
padding: '15px 25px',
margin: '0 10px',
fontSize: '16px',
backgroundColor: '#4CAF50',
color: 'white',
border: 'none',
borderRadius: '5px',
cursor: 'pointer'
}
};
馃摑 Ejemplo Pr谩ctico: Formulario de Tareas
jsx
function AppTareas() {
const [tareas, setTareas] = useState([]);
// Funci贸n para agregar tarea desde el hijo
const agregarTarea = (nuevaTarea) => {
setTareas([...tareas, {
id: Date.now(),
texto: nuevaTarea,
completada: false
}]);
};
return (
<div style={{ maxWidth: '600px', margin: '0 auto', padding: '20px' }}>
<h1>馃搵 Lista de Tareas</h1>
{/* Paso la funci贸n al formulario hijo */}
<FormularioTarea onAgregarTarea={agregarTarea} />
{/* Lista de tareas */}
<div style={{ marginTop: '30px' }}>
<h3>Tareas ({tareas.length})</h3>
{tareas.map(tarea => (
<div key={tarea.id} style={styles.tarea}>
{tarea.texto}
</div>
))}
</div>
</div>
);
}
function FormularioTarea({ onAgregarTarea }) {
const [input, setInput] = useState("");
const manejarSubmit = (e) => {
e.preventDefault();
if (input.trim()) {
// ⭐ Llamo a la funci贸n del padre con mi dato
onAgregarTarea(input);
setInput("");
}
};
return (
<form onSubmit={manejarSubmit} style={styles.form}>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Nueva tarea..."
style={styles.input}
/>
<button type="submit" style={styles.botonAgregar}>
Agregar Tarea
</button>
</form>
);
}
const styles = {
form: {
display: 'flex',
gap: '10px',
marginBottom: '20px'
},
input: {
flex: 1,
padding: '12px',
fontSize: '16px',
border: '2px solid #ddd',
borderRadius: '4px'
},
botonAgregar: {
padding: '12px 24px',
backgroundColor: '#2196F3',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '16px'
},
tarea: {
backgroundColor: '#f5f5f5',
padding: '15px',
marginBottom: '10px',
borderRadius: '4px',
borderLeft: '4px solid #4CAF50'
}
};
馃帗 Explicaci贸n Visual del Flujo
Del Padre al Hijo
text
PADRE ──[props]──> HIJO
(datos: string, number, array, object)
Del Hijo al Padre
text
PADRE ──[funci贸n]──> HIJO
⬆
HIJO ──[datos]──> PADRE
(ejecuta la funci贸n con datos)
馃搶 Reglas de Oro
1. Los Props Son de Solo Lectura
jsx
// ❌ NO HAGAS ESTO
function Hijo(props) {
props.mensaje = "Cambiado"; // ERROR
return <div>{props.mensaje}</div>;
}
// ✅ HAZ ESTO
function Hijo({ mensaje }) {
return <div>{mensaje}</div>; // Solo lectura
}
2. Tipos de Datos que se Pueden Pasar
jsx
<PasoDeDatos
texto="Hola" // String
numero={42} // Number
booleano={true} // Boolean
arreglo={[1, 2, 3]} // Array
objeto={{nombre: "Ana"}} // Object
funcion={() => {}} // Function
elemento={<div>Hola</div>} // JSX
componente={<MiComponente />} // Componente
/>
3. Patr贸n Com煤n: Lift State Up
jsx
// El estado vive en el componente m谩s alto que lo necesita
function Abuelo() {
const [estado, setEstado] = useState(""); // Estado aqu铆
return (
<Padre
estado={estado}
setEstado={setEstado}
/>
);
}
function Padre({ estado, setEstado }) {
return <Hijo estado={estado} setEstado={setEstado} />;
}
function Hijo({ estado, setEstado }) {
// Todos pueden leer y actualizar el estado
return <button onClick={() => setEstado("Nuevo")}>Cambiar</button>;
}
馃殌 Ejemplo Final: Chat Padre-Hijo
jsx
function ChatApp() {
const [mensajes, setMensajes] = useState([
{ id: 1, texto: "Hola hijo!", de: "padre" },
{ id: 2, texto: "Hola padre!", de: "hijo" }
]);
const agregarMensaje = (texto, autor) => {
setMensajes([...mensajes, {
id: Date.now(),
texto,
de: autor
}]);
};
return (
<div style={styles.chatContainer}>
<h1>馃挰 Chat Padre-Hijo</h1>
<div style={styles.mensajes}>
{mensajes.map(msg => (
<div
key={msg.id}
style={{
...styles.mensaje,
alignSelf: msg.de === 'padre' ? 'flex-start' : 'flex-end',
backgroundColor: msg.de === 'padre' ? '#e3f2fd' : '#fce4ec'
}}
>
{msg.texto}
</div>
))}
</div>
<div style={styles.controles}>
<PadreChat onEnviar={texto => agregarMensaje(texto, 'padre')} />
<HijoChat onEnviar={texto => agregarMensaje(texto, 'hijo')} />
</div>
</div>
);
}
function PadreChat({ onEnviar }) {
const [input, setInput] = useState("");
return (
<div style={styles.chatBox}>
<h3>馃懆 Padre</h3>
<input
value={input}
onChange={e => setInput(e.target.value)}
placeholder="Escribe al hijo..."
/>
<button onClick={() => { onEnviar(input); setInput(""); }}>
Enviar al Hijo
</button>
</div>
);
}
function HijoChat({ onEnviar }) {
const [input, setInput] = useState("");
return (
<div style={styles.chatBox}>
<h3>馃懄 Hijo</h3>
<input
value={input}
onChange={e => setInput(e.target.value)}
placeholder="Escribe al padre..."
/>
<button onClick={() => { onEnviar(input); setInput(""); }}>
Enviar al Padre
</button>
</div>
);
}
const styles = {
chatContainer: {
maxWidth: '800px',
margin: '0 auto',
padding: '20px'
},
mensajes: {
display: 'flex',
flexDirection: 'column',
gap: '10px',
height: '300px',
overflowY: 'auto',
padding: '20px',
backgroundColor: '#f5f5f5',
borderRadius: '10px',
marginBottom: '20px'
},
mensaje: {
padding: '10px 15px',
borderRadius: '15px',
maxWidth: '60%'
},
controles: {
display: 'flex',
gap: '20px'
},
chatBox: {
flex: 1,
padding: '20px',
backgroundColor: '#e8f5e9',
borderRadius: '10px'
}
};
✅ Resumen
Flujo Completo Hijo → Padre:
Padre define una funci贸n que recibe datos
Padre pasa esa funci贸n al hijo como prop
Hijo ejecuta esa funci贸n con sus datos
Padre recibe los datos y actualiza su estado
¡Ahora puedes hacer que tus componentes se comuniquen en ambas direcciones
Comentarios
Publicar un comentario