Inicio / Artículos / Notas prácticas: Cómo optimicé una app React lenta sin volver a escribirla

Notas prácticas: Cómo optimicé una app React lenta sin volver a escribirla

Guía práctica paso a paso: Cómo optimicé una aplicación React lenta sin reescribirla: contratos, verificaciones y espacios para código adicional para equipos que implementan este patrón.

1621 palabras

Úselo como una versión reestructurada dirigida a los operadores de las ideas presentadas en “Cómo optimicé una aplicación React lenta sin reescribirla”: etapas claras, espacios ordenados para el código y notas de recuperación que perduran tras la transferencia de tareas. La etapa de Resumen funciona mejor cuando se considera como una superficie medible. Capture una transcripción clave, un caso de fallo y la nota de reversión antes de ampliar el alcance. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace completaciones parciales silenciosas.

El diagnóstico: encontrar el problema

Para determinar la etapa del diagnóstico, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo de tokens o consultas junto con los resultados funcionales. La visibilidad temprana del costo evita facturas inesperadas cuando el flujo pasa de entornos de demostración a entornos compartidos. Asocie el estado con el componente que gestiona la mutación; llevar todo a un almacén global dificulta detectar errores relacionados con los tiempos de ejecución.

1. React.memo: La solución más sencilla

Para el memo de React, define las entradas, el responsable de la etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa desde un punto de control conocido sin tener que adivinar el estado oculto. Mantén la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el grafo. Coloca el estado junto con el componente que es responsable de la mutación. Subir todo a un almacén global hace que los errores relacionados con el tiempo sean más difíciles de detectar.

const ExpensiveComponent = React.memo(({ data, onUpdate }) => {
  // Component logic
});

2. useMemo y useCallback: Detener los cálculos recursivos

En las etapas de useMemo y useCallback, defina los parámetros de entrada, el responsable de cada paso y los criterios para finalizarlo antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Coloque el estado junto al componente que gestiona la mutación. Subir todo a un almacén global hace que los errores de sincronización sean más difíciles de detectar. En las etapas de useMemo y useCallback, defina los parámetros de entrada, el responsable de cada paso y los criterios para finalizarlo antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Considere esta etapa como un contrato entre los parámetros de entrada y los resultados validados. Asigne nombres a los elementos generados, defina comprobaciones de éxito y evite las completaciones parciales silenciosas.

const computedStats = useMemo(() => {
  return expensiveAggregation(data);
}, [data]);
const handleUpdate = useCallback((id) => {
  updateItem(id);
}, []);

3. useTransition: Priorizar las interacciones del usuario

Al trabajar en la fase de priorización de interacciones mediante useTransition, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación ayuda a mantener honestos los cambios posteriores en el código. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la versión de demostración a entornos compartidos. Trate los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización.

const [isPending, startTransition] = useTransition();
const handleSearch = (term) => {
  startTransition(() => {
    setSearchTerm(term);
    // Filtering happens in the background
  });
};

4. useDeferredValue: Suavizar las renderizaciones costosas

Al trabajar en la etapa 4 de useDeferredValue Smoothing Out, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Trate los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización.

const deferredData = useDeferredValue(data);
// Chart receives deferredData and updates only when React has idle time

5. Virtualización: Renderizar solo lo que es visible

Al trabajar en la etapa 5 de “Solo renderizado por virtualización”, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación garantiza que los cambios posteriores en el código sean transparentes. Documente tanto la ruta de éxito como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no de mejoras posteriores. Trate los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante el renderizado. Al trabajar en la etapa 5 de “Solo renderizado por virtualización”, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación garantiza que los cambios posteriores en el código sean transparentes. Considere esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.

import { FixedSizeList } from 'react-window';
const Row = ({ index, style }) => (
  <div style={style}>
    {data[index].name}
  </div>
);
<FixedSizeList
  height={400}
  itemCount={data.length}
  itemSize={35}
  width="100%"
>
  {Row}
</FixedSizeList>

6. Carga perezosa: División del código por ruta

La etapa 6 de carga perezosa funciona mejor cuando se trata como un área medible. Registre una transcripción ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Anote los tiempos de ejecución y el costo en tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando la ruta pasa de un entorno de demostración a entornos compartidos. Mantenga el trabajo de renderizado económico y posponga las operaciones costosas a la memorización solo después de realizar mediciones; una memorización prematura puede ocultar errores en los propios.

const Dashboard = lazy(() => import('./views/Dashboard'));
const Analytics = lazy(() => import('./views/Analytics'));
function App() {
  return (
    <Suspense fallback={<Loading />}>
      <Routes>
        <Route path="/" element={<Dashboard />} />
        <Route path="/analytics" element={<Analytics />} />
      </Routes>
    </Suspense>
  );
}

7. useMemoizedSelector: Optimización de la gestión del estado

La etapa 7 de gestión de estado useMemoizedSelector funciona mejor cuando se trata como una superficie medible. Capture una transcripción ejemplar, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el grafo. Mantenga el proceso de renderizado económico y posponga las derivaciones costosas detrás de la memorización solo después de realizar mediciones. La memorización prematura puede ocultar errores en los props obsoletos.

import { createSelector } from '@reduxjs/toolkit';
const selectFilteredData = createSelector(
  (state) => state.items,
  (state) => state.filterTerm,
  (items, term) => items.filter(item =>
    item.name.toLowerCase().includes(term.toLowerCase())
  )
);
// In component:
const filteredData = useSelector(selectFilteredData);

Las cifras: antes y después

La etapa “The Numbers Before” funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Documente tanto el camino óptimo como el de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son ajustes realizados posteriormente. Mantenga los procesos de renderizado económicos y reserve las derivaciones costosas para la memorización solo después de realizar mediciones; una memorización prematura puede ocultar errores en los datos. La etapa “The Numbers Before” funciona mejor cuando se trata como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Considere esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas.

Cambio de mentalidad

En la fase de cambio de mentalidad, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo en tokens o consultas junto con los resultados funcionales. La visibilidad temprana de los costos evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Coloque el estado junto al componente que es responsable de la mutación; llevar todo a un almacén global hace que los errores relacionados con los tiempos de ejecución sean más difíciles de detectar.

Conclusión

En la etapa The Bottom Line, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben encontrarse en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema. Mantenga el estado junto al componente que gestiona la mutación. Al almacenar todo en un almacén global, resulta más difícil detectar errores relacionados con los tiempos de ejecución.

Lista de verificación operativa

Al trabajar en la etapa de la lista de verificación operativa, primero escriba el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista garantiza que los cambios posteriores en el código sean transparentes.

Preferir unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el error debe indicar una única responsabilidad y no un proceso complicado.

Tratar los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización.

Fijar las versiones de las dependencias y registrar el resumen de la imagen utilizada en la demostración. La reproducibilidad es mejor que el conocimiento tribal.

Considerar esta etapa como un contrato entre las entradas y las salidas validadas. Nombrar los artefactos, definir las comprobaciones de éxito y rechazar completaciones parciales silenciosas.

Tratar los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización.

Antes de promocionar el conjunto de herramientas, congele las versiones, capture una transcripción de referencia para la ruta crítica y confirme los pasos para revertir cambios. Los entornos compartidos requieren límites de velocidad, verificaciones de asignación y un responsable claro para la rotación de credenciales secretas. Prefiera una fiabilidad sólida a demostraciones ingeniosas pero puntuales.

Nota para el lote d6a7f4e83dda: mantenga las claves del proveedor fuera del repositorio, establezca un límite para tokens por sesión y almacene las transcripciones junto a los archivos de prueba para que los cambios en los modelos posteriores sigan siendo comparables.