Curso react nivel medio

Introducción
useTransition es un hook de React diseñado para manejar transiciones de estado de forma más fluida, especialmente en aplicaciones donde cambios de estado complejos pueden causar bloqueos en la interfaz de usuario. Este hook permite clasificar actualizaciones como urgentes o no urgentes, asegurando que la interfaz mantenga su interactividad mientras React procesa los cambios.


¿Qué es useTransition?

  • Propósito: Manejar actualizaciones no urgentes, como filtros o animaciones, que no deben bloquear la UI.
  • Estado dual:
    • Actualizaciones urgentes: Responden de inmediato, como clics o entradas de texto.
    • Actualizaciones no urgentes: Procesan tareas más complejas, como cálculos o filtrado.

Sintaxis

1const [isPending, startTransition] = useTransition();
  • isPending: Booleano que indica si la transición está en progreso.
  • startTransition: Función que encapsula la lógica de actualización no urgente.

Ejemplo Básico: Transición de Estado

Código

1import React, { useState, useTransition } from "react";
2
3function ListaPesada() {
4  const [filtro, setFiltro] = useState("");
5  const [lista, setLista] = useState([]);
6  const [isPending, startTransition] = useTransition();
7
8  const manejarCambio = (e) => {
9    const valor = e.target.value;
10    setFiltro(valor);
11
12    startTransition(() => {
13      const nuevaLista = Array.from({ length: 20000 }, (_, i) => `Elemento ${i}`)
14        .filter((item) => item.includes(valor));
15      setLista(nuevaLista);
16    });
17  };
18
19  return (
20    <div>
21      <input
22        type="text"
23        value={filtro}
24        onChange={manejarCambio}
25        placeholder="Filtrar lista"
26      />
27      {isPending && <p>Cargando...</p>}
28      <ul>
29        {lista.map((item, index) => (
30          <li key={index}>{item}</li>
31        ))}
32      </ul>
33    </div>
34  );
35}
36
37export default ListaPesada;

Explicación

  1. isPending:
    • Muestra un mensaje de "Cargando..." mientras la lista se actualiza.
  2. startTransition:
    • Encapsula la lógica de filtrado para que sea una actualización no urgente.
  3. Rendimiento Mejorado:
    • La entrada del usuario sigue respondiendo de forma inmediata mientras se procesa la actualización.

Caso Práctico: Filtro en una Tabla

Código

1import React, { useState, useTransition } from "react";
2
3function Tabla() {
4  const [filtro, setFiltro] = useState("");
5  const [datos, setDatos] = useState(
6    Array.from({ length: 10000 }, (_, i) => ({
7      id: i,
8      nombre: `Nombre ${i}`,
9    }))
10  );
11  const [resultados, setResultados] = useState(datos);
12  const [isPending, startTransition] = useTransition();
13
14  const manejarFiltro = (e) => {
15    const valor = e.target.value;
16    setFiltro(valor);
17
18    startTransition(() => {
19      const nuevosResultados = datos.filter((item) =>
20        item.nombre.toLowerCase().includes(valor.toLowerCase())
21      );
22      setResultados(nuevosResultados);
23    });
24  };
25
26  return (
27    <div>
28      <input
29        type="text"
30        value={filtro}
31        onChange={manejarFiltro}
32        placeholder="Filtrar por nombre"
33      />
34      {isPending && <p>Filtrando datos...</p>}
35      <table>
36        <thead>
37          <tr>
38            <th>ID</th>
39            <th>Nombre</th>
40          </tr>
41        </thead>
42        <tbody>
43          {resultados.map((item) => (
44            <tr key={item.id}>
45              <td>{item.id}</td>
46              <td>{item.nombre}</td>
47            </tr>
48          ))}
49        </tbody>
50      </table>
51    </div>
52  );
53}
54
55export default Tabla;

Explicación

  1. Filtrar Datos:
    • startTransition encapsula la lógica de filtrado para evitar bloquear la entrada del usuario.
  2. isPending:
    • Muestra un indicador mientras se actualiza la tabla.
  3. Eficiencia:
    • La tabla no se vuelve a renderizar hasta que la transición haya completado el filtrado.

Diferencias con useDeferredValue

CaracterísticauseTransitionuseDeferredValue
PropósitoClasificar actualizaciones como urgentes o no urgentesDiferir el valor para actualizaciones no urgentes
Indicador (isPending)No
Uso ComúnActualizaciones complejas que afectan el estadoRetrasar actualizaciones de UI con datos procesados

Limitaciones de useTransition

  1. Solo para Actualizaciones de Estado:

    • Solo funciona para diferir actualizaciones de estado, no para tareas generales como fetch de datos.
  2. Diseñado para Fluidez:

    • No mejora directamente el rendimiento en cálculos costosos; solo mantiene la UI interactiva.
  3. Dependiente del Código Reactivo:

    • No sustituye optimizaciones manuales como memoización o división de carga.

Buenas Prácticas con useTransition

  1. Evitar Sobreuso:

    • No encapsules todas las actualizaciones; úsalo solo para tareas no urgentes que afecten la experiencia del usuario.
  2. Combinar con Memoización:

    • Usa React.memo o useMemo para evitar renderizados innecesarios.
  3. Indicadores Claros:

    • Proporciona retroalimentación visual usando isPending para mostrar el progreso.

Ejemplo Completo: Filtro y Contador Simultáneo

Código

1import React, { useState, useTransition } from "react";
2
3function App() {
4  const [contador, setContador] = useState(0);
5  const [filtro, setFiltro] = useState("");
6  const [lista, setLista] = useState(
7    Array.from({ length: 10000 }, (_, i) => `Elemento ${i}`)
8  );
9  const [resultados, setResultados] = useState(lista);
10  const [isPending, startTransition] = useTransition();
11
12  const manejarFiltro = (e) => {
13    const valor = e.target.value;
14    setFiltro(valor);
15
16    startTransition(() => {
17      const nuevosResultados = lista.filter((item) =>
18        item.toLowerCase().includes(valor.toLowerCase())
19      );
20      setResultados(nuevosResultados);
21    });
22  };
23
24  return (
25    <div>
26      <h1>Ejemplo Completo</h1>
27      <button onClick={() => setContador((prev) => prev + 1)}>
28        Incrementar Contador ({contador})
29      </button>
30      <input
31        type="text"
32        value={filtro}
33        onChange={manejarFiltro}
34        placeholder="Filtrar lista"
35      />
36      {isPending && <p>Filtrando...</p>}
37      <ul>
38        {resultados.map((item, index) => (
39          <li key={index}>{item}</li>
40        ))}
41      </ul>
42    </div>
43  );
44}
45
46export default App;

Explicación

  1. Estado Urgente:
    • El contador responde de inmediato.
  2. Estado No Urgente:
    • La lista se actualiza con una transición, manteniendo fluidez.

Conclusión

useTransition es una herramienta poderosa para manejar actualizaciones no urgentes, mejorando la fluidez en aplicaciones complejas. Úsalo para:

  • Filtros de grandes listas.
  • Tareas costosas que no deben bloquear la UI.
  • Actualizaciones visuales que pueden esperar.