Notas prácticas: Los componentes de React deben ser puros — el secreto detrás de StrictMode
Guía práctica paso a paso de las notas prácticas: Los componentes React deben ser puros — el secreto detrás de StrictMode: contratos, verificaciones y espacios para código reutilizable para los equipos que implementan este patrón.
Úselo como una versión reestructurada dirigida a los operadores de las ideas presentadas en “React Components Must Be Pure — the Secret Behind StrictMode and the Compiler”: etapas claras, espacios ordenados para el código y notas de recuperación que sobreviven a la transferencia de tareas. La etapa de Resumen funciona mejor cuando se trata como una superficie medible. Capture una transcripción clave, 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 completaciones parciales silenciosas.
¿Qué es una función pura?
Para la etapa “¿Qué es puro?”, defina las entradas, el propietario 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. 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. 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.
// ✅ pure function — same input, same output, and it touches nothing outside
function double(x: number): number {
return x * 2;
}
double(3); // 6
double(3); // 6 — six no matter how many times you call it
// 🔴 impure function — it changes the outer variable `total` (a side effect)
let total = 0;
function addToTotal(x: number): number {
total += x; // side effect!
return total; // the result changes on every call
}
addToTotal(3); // 3
addToTotal(3); // 6 — same input, different result
Un componente también es una función pura
Para el componente A, que es una etapa, defina las entradas, el responsable de dicha 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. 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. Coloque el estado junto con el componente que gestiona la mutación. Al llevar todo a un almacén global, resulta más difícil detectar errores relacionados con los tiempos de ejecución.
type Props = { name: string };
// ✅ pure — same name, always the same result
function Greeting({ name }: Props) {
return <h1>Hello, {name}!</h1>;
}
Incumplir la regla: no tocar elementos externos durante el renderizado
En la etapa de Break the Rule Don, 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. 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 es responsable de la mutación. Subir todo a un almacenamiento global hace que los errores relacionados con el tiempo sean más difíciles de detectar. En la etapa de Break the Rule Don, 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. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.
let count = 0; // a variable outside the component
// 🔴 not pure — changes an external variable while rendering
function Counter() {
count = count + 1; // side effect!
return <p>{count}</p>;
}
Ejecútelo usted mismo: ¿por qué aparece el “2”?
Al trabajar en la fase de “Ejecútelo usted mismo: ¿por qué?”, anote primero el contrato: entradas requeridas, 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. 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 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.
import { useState } from 'react';
let count = 0;
function Counter() {
const [, setTick] = useState(0); // a device to trigger re-renders
count = count + 1; // 🔴 changes an external variable on every render
return (
<div>
<p>{count}</p>
<button onClick={() => setTick((n) => n + 1)}>Re-render</button>
</div>
);
}
// ✅ pure — computed from input (props) alone
function Counter({ count }: { count: number }) {
return <p>{count}</p>;
}
Pero puede cambiar “los elementos generados durante la renderización”
Al trabajar en la etapa “Pero puedes cambiarlo”, anota primero el contrato: los datos necesarios, la señal de éxito y qué ocurre en caso de un fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Mantén 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 estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el código. Considera los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización.
function ProductList({ products }: { products: Product[] }) {
// ✅ this array was just created in this render — handle it however you like
const sorted = [...products].sort((a, b) => a.price - b.price);
return (
<ul>
{sorted.map((p) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
);
}
Misterio 1 resuelto: por qué StrictMode ejecuta las cosas dos veces
Al trabajar en la fase de “Mystery 1 Solved Why”, anote primero el contrato: los datos necesarios, 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. 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 de mejoras posteriores. Trate los efectos secundarios como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización. Al trabajar en la fase de “Mystery 1 Solved Why”, anote primero el contrato: los datos necesarios, 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. Considere esta fase como un contrato entre los datos de entrada y las salidas validadas. Asigne nombres a los artefactos, defina las comprobaciones de éxito y rechace las completaciones parciales silenciosas.
// main.tsx — in development, the components inside this render twice
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);
¿Entonces, dónde van los efectos secundarios?
Por lo tanto, los trabajos en segundo plano funcionan mejor cuando se tratan como una superficie medible. Capture un registro exitoso, un caso de fallo y la nota de reversión antes de ampliar el alcance. 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 demostración a entornos compartidos. Mantenga los procesos de renderizado económicos y posponga las derivaciones costosas a la memorización solo después de realizar mediciones; una memorización prematura puede ocultar errores en los valores utilizados.
// 🔴 side effect during rendering — fires on every render
function ProductPage({ id }: { id: number }) {
logView(id); // a side effect in the render body — not allowed
return <h1>Product {id}</h1>;
}
// ✅ in an event handler — runs only at the moment the user clicks
function BuyButton({ id }: { id: number }) {
return <button onClick={() => logPurchase(id)}>Buy</button>;
}
Misterio 2 resuelto: por qué el compilador de React depende de la pureza
El misterio de The Mystery 2 resuelto: por qué la etapa funciona mejor cuando se trata como una superficie medible. Capture un registro exitoso, 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 sistema. Haga que el proceso de renderizado sea económico y posponga las derivaciones costosas a la memorización solo después de realizar mediciones. Una memorización prematura puede ocultar errores en los propios.
// 🔴 not pure → the compiler skips optimization (ESLint points at this component)
let renderCount = 0;
function RenderCounter() {
renderCount++; // mutating an external variable during render — a violation
return <p>{renderCount}</p>;
}
// ✅ pure → the compiler memoizes automatically (reuse the previous result when inputs match)
function Label({ text }: { text: string }) {
return <p>{text}</p>;
}
function App() {
return (
<>
<RenderCounter />
<Label text="Pure Component" />
</>
);
}
export default App;
Viendo la interfaz de usuario como un árbol
La interfaz Seeing UI como escenario 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 mejoras posteriores. Mantenga los procesos de renderizado económicos y posponga las derivaciones costosas a la memorización solo después de realizar mediciones; una memorización prematura puede ocultar errores en los propios. La interfaz Seeing UI como escenario 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. Trate este escenario 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.
function App() {
return <ProductList products={products} />;
}
function ProductList({ products }: { products: Product[] }) {
return (
<ul>
{products.map((p) => (
<ProductCard key={p.id} product={p} />
))}
</ul>
);
}
App
└─ ProductList
├─ ProductCard
├─ ProductCard
└─ ProductCard
Conclusión
En la fase de cierre, 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. Asocie el estado al componente que gestiona la mutación; llevar todo a un almacén global dificulta detectar errores relacionados con los tiempos de ejecución.
Referencias
En la fase de Referencias, 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. Mantenga 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 estar en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema. Coloque el estado junto al componente que gestiona la mutación. Al llevar todo a un almacén global, resulta más difícil detectar errores de sincronización.
Lista de verificación operativa
Al trabajar en la fase 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 verificaciones 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 d707b555add8: 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.