Aprende qué es Lifting State Up en React y cuándo usarlo

Gabriel Jiménez | Hace 5 meses

Cuando aprendemos a programar en React, uno de los principales problemas al que nos enfrentamos es: compartir un mismo estado entre diferentes componentes. Para evitar este problema, encapsulamos toda nuestra lógica en un componente. Sin embargo, cuando las aplicaciones crecen esto no suele ser mantenible a largo plazo. Otra alternativa es utilizar la técnica Lifting State Up, pero no todos saben de qué trata.

Aprendamos qué es Lifting State Up, cómo y por qué utilizarlo y finalmente, veamos un ejemplo práctico.

¿Qué es Lifting State Up en React?

Es una técnica o patrón para mantener dos o más componentes sincronizados a partir de un mismo estado. El estado debe ser gestionado por el componente padre más cercano o es su defecto, crear uno nuevo.

Para entenderlo mejor, analicemos la figura 1.
Figura 1. Ejemplo del uso de Lifting State Up en React.


El flujo es el siguiente:
 
  1. Usuario escribe en el campo nombre dentro del componente Formulario.
  2. El Formulario Informa a su componente padre (Control central de datos) que el estado necesita actualizarse.
  3. Control central de datos actualiza el estado.
  4. Control central devuelve el estado nombre actualizado al Formulario.
  5. Control central devuelve el estado nombre actualizado al componente Tarjeta de saludo.
  6. Finalmente, el usuario ve actualizado correctamente lo que está escribiendo.

En resumen, el componente Control central de datos trabaja como: fuente única de verdad del estado nombre.


Por qué y cuando usar Lifting State Up

Lifting State Up es importante porque, nos obliga a mantener una mentalidad de separación de responsabilidades. Al hacerlo, estamos haciendo que nuestros componentes sean escalables y fáciles de mantener.


En nuestro ejemplo de la Figura 1, la responsabilidad es: mantener el estado nombre como única fuente de verdad y sincronizarlo con sus dependientes. Ya que se el por qué, ahora como detecto que debo utilizarlo.


Algunas señales son:


  • Varios componentes depende de la misma data
  • Quieres mantener una única fuente de verdad
  • Un valor en un componente afecta a otro
  • Estados duplicados en varios componentes



Ejemplo práctico paso a paso

Para ejemplificar el uso de Lifting State Up, supongamos que necesitamos una aplicación para listar y dar de alta películas.


Una solución sería crear un único componente donde se realicen ambas tareas, pero como ya vimos anteriormente, separa responsabilidades es útil y sano para nuestras aplicaciones.


Para nuestro caso, tenemos tres componentes con responsabilidades bien definidas:


Componente MovieForm

Se encarga de crear y notificar a su componente padre sobre las películas creadas.

import { useState } from 'react';

function MovieForm({ onChange }) {
  const [name, setName] = useState('');
  const [rating, setRating] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();

    if (!name || !rating) return;

    onChange({ name, rating: Number(rating) });

    setName('');
    setRating('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        placeholder="Nombre de la película"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <input
        placeholder="Puntuación"
        type="number"
        value={rating}
        onChange={(e) => setRating(e.target.value)}
      />
      <button type="submit">Agregar</button>
    </form>
  );
}

export default MovieForm;

Componente MoveList

Lista las películas almacenadas en el componte App.

function MovieList({ movies }) {
  return (
    <ul>
      {movies.map((movie, index) => (
        <li key={index}>
          {movie.name} - Puntuación: {movie.rating}
        </li>
      ))}
    </ul>
  );
}

export default MovieList;

Componente App

Trabaja como única fuente de verdad de las películas creadas. Además, permite sincronizarlas con el componente MovieList.

import { useState } from 'react';
import MovieForm from './MovieForm';
import MovieList from './MovieList';

function App() {
  const [movies, setMovies] = useState([]);

  const handleAddMovie = (movie) => {
    setMovies((prev) => [...prev, movie]);
  };

  return (
    <>
      <MovieForm onChange={handleAddMovie} />
      <MovieList movies={movies} />
    </>
  );
}

export default App;


Nota: Saber que props debo de pasar a mis componentes es otra buena práctica en el desarrollo de software en React. Te recomiendo que leas mi artículo: React props: buenas prácticas para código más limpio y escalable


Conclusión

Lifting State Up nos hace tener una mentalidad de separación de responsabilidades al mantener nuestros componentes como fuente única de verdad. Sin embargo, es importante no abusar porque no es lo mismo sincronizar data entre uno o dos componentes que hacerlo con más de diez.

Si quieres aprender más sobre como mejorar la calidad de tu código en tus aplicaciones React, te recomiendo mi programa: Mentalidad de pruebas