Pasar propiedades de hijo a padre en React

 

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

1-Sistema de Tareas en React

0-Gestión de estado en una aplicación de tareas

2-Agregar una Tarea a tu Lista de Tareas en React