Pasar propiedades de hijo a padre en React

 

 DUDA 1: ¿Qué es const saludar = (nombre) => { ... }?

Explicación simple:

javascript
const saludar = (nombre) => {
  alert(`Hola ${nombre}`);
};

Esto  define una función. Piensa en const saludar como un nombre para la función. Es equivalente a:

javascript
function saludar(nombre) {
  alert(`Hola ${nombre}`);
}

Analogía:

  • const saludar = "Voy a guardar algo en una caja llamada 'saludar'"

  • = (nombre) => { alert(...) } = "Lo que guardo es una función que recibe 'nombre' y muestra alerta"

Cómo se puede usar:

javascript
// Opción 1: Llamarla directamente
saludar("Juan");  // Muestra: "Hola Juan"

// Opción 2: Pasar la función como referencia
const miFuncion = saludar;  // Guarda la función en otra variable
miFuncion("Ana");          // Muestra: "Hola Ana"

📌 DUDA 2: ¿Por qué a veces se usa () => saludar("Mundo") y a veces saludar?

Esta es la clave para entender React. Hay dos casos diferentes:

CASO A: Cuando la función NO necesita parámetros

jsx
// En el padre
const mostrarMensaje = () => {
  alert("¡Hola!");
};

// En el return
<Accion 
  accion={mostrarMensaje}  // ← SIN paréntesis, SIN arrow function adicional
  texto="Saludar" 
/>

¿Por qué?

  • mostrarMensaje ya es una función lista para ejecutar

  • No necesita parámetros adicionales

  • Solo pasamos la referencia (el "teléfono" de la función)

CASO B: Cuando la función SÍ necesita parámetros

jsx
// En el padre
const saludar = (nombre) => {
  alert(`Hola ${nombre}`);
};

// En el return
<Accion 
  accion={() => saludar("Mundo")}  // ← CON arrow function que envuelve
  texto="Saludar" 
/>

¿Por qué la arrow function extra?

  1. saludar("Mundo") → Ejecuta inmediatamente (¡ERROR!)

  2. () => saludar("Mundo") → Crea una nueva función que, cuando se ejecute, llamará a saludar("Mundo")


🎯 Comparación Visual:

jsx
// EJEMPLO 1: Sin parámetros
const saludarSimple = () => {
  alert("¡Hola Mundo!");
};

// En el return → PASO DIRECTO
<Accion accion={saludarSimple} />

// EJEMPLO 2: Con parámetros
const saludarConNombre = (nombre) => {
  alert(`Hola ${nombre}`);
};

// En el return → ENVOLVIENDO CON ARROW FUNCTION
<Accion accion={() => saludarConNombre("Mundo")} />

🔍 Entendiendo la Diferencia con Ejemplos:

Ejemplo 1: Lo que NO debes hacer (ERROR COMÚN)

jsx
// ❌ MAL: Se ejecuta inmediatamente al renderizar
<Accion accion={saludar("Mundo")} />
// Esto muestra la alerta INMEDIATAMENTE al cargar la página

// ✅ BIEN: Se crea una función que se ejecutará después
<Accion accion={() => saludar("Mundo")} />
// Esto muestra la alerta SOLO cuando hagan clic

Ejemplo 2: Alternativa correcta

jsx
// También podrías hacer esto:
const saludarMundo = () => {
  saludar("Mundo");
};

// Y luego pasar la referencia
<Accion accion={saludarMundo} />

🧠 Regla Muy Simple para Recordar:

javascript
// Si tu función original NO tiene parámetros:
<Componente funcion={nombreFuncion} />

// Si tu función original SÍ tiene parámetros:
<Componente funcion={() => nombreFuncion(parametro)} />

🎮 Ejemplo Práctico para Entender:

Imagina estas funciones:

javascript
// Función A: No necesita información adicional
const encenderLuz = () => {
  console.log("Luz encendida");
};

// Función B: Necesita saber QUÉ luz encender
const encenderLuzEspecifica = (nombreLuz) => {
  console.log(`Encendiendo: ${nombreLuz}`);
};

Cómo las pasarías a un botón:

jsx
// Botón 1: Solo encender (sin especificar cuál)
<Boton 
  accion={encenderLuz}  // ← Directo, no necesita preparación
  texto="Encender"
/>

// Botón 2: Encender luz específica
<Boton 
  accion={() => encenderLuzEspecifica("Sala")}  // ← Prepara la llamada
  texto="Encender luz de Sala"
/>

📚 Resumen Final:

  1. const miFuncion = () => { ... } → Sí define una función

  2. miFuncion → Es la referencia a la función (se pasa cuando no hay parámetros)

  3. () => miFuncion(param) → Crea una nueva función que llama a la original con parámetros

  4. miFuncion(param) → Ejecuta inmediatamente (generalmente ERROR en React)


💡 Ejercicio Mental:

Si vieras esto:

jsx
<Accion 
  accion={saludar} 
  texto="Saludar" 
/>

¿Cómo tendría que estar definida saludar?

javascript
const saludar = () => {
  // ¿Qué pondrías aquí?
};

Respuesta: Tendría que ser una función que NO requiera parámetros, por ejemplo:

javascript
const saludar = () => {
  alert("¡Hola a todos!");
};


Componente Padre: AppSaludo.js

jsx
function AppSaludo() {
  const saludar = (nombre) => {
    alert(`Hola ${nombre}`);
  };

  return (
    <div>
      <Accion 
        accion={() => saludar("Mundo")} 
        texto="Saludar" 
      />
    </div>
  );
}

Componente Hijo: Accion.js

jsx
function Accion({ accion, texto }) {
  return (
    <button 
      onClick={accion}
      style={{
        padding: "10px 20px",
        margin: "10px",
        backgroundColor: "green",
        color: "white",
        border: "none",
        borderRadius: "5px"
      }}
    >
      {texto}
    </button>
  );
}

Componente Padre: AppCalculo.js

jsx
function AppCalculo() {
  const sumar = (a, b) => {
    return a + b;
  };

  const multiplicar = (a, b) => {
    return a * b;
  };

  return (
    <div>
      <Resultado 
        calcular={() => sumar(5, 3)} 
        titulo="Sumar 5 + 3" 
      />
      <Resultado 
        calcular={() => sumar(10, 7)} 
        titulo="Sumar 10 + 7" 
      />
    </div>
  );
}

Componente Hijo: Resultado.js

function Resultado({ calcular, titulo }) {
  return (
    <div style={{
      border: '1px solid orange',
      padding: '15px',
      margin: '10px',
      borderRadius: '8px'
    }}>
      <h4>{titulo}</h4>
      <p>Resultado: {calcular()}</p>
    </div>
  );
}

**********************************************

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

  1. En el componente padre: Define una función que manejará los datos recibidos del hijo.

  2. Pasa la función como prop al componente hijo.

  3. En el componente hijo: Recibe la función como prop y la llama cuando necesite enviar datos al padre.

  4. 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

Entradas más populares de este blog

9.3-Tutorial de Componentes React con Props -SSS

9.6-Ciclo de Vida de un Componente React

9-Componentes en React-estado