Mejores prácticas de React 19
Un resumen condensado de las 25 mejores prácticas más importantes extraídas de todas las páginas de esta sección.
- Instala @types/react 19 Juntas:
@types/reacty@types/react-domdeben actualizarse en la misma instalación a la línea v19; las versiones no coincidentes producen errores de tipo confusos (por ejemplo,reffalta enComponentProps) que parecen errores de React. - Usa Context Directamente como Proveedor:
<Context.Provider value={…}>está deprecado — renderiza<ThemeContext value={theme}>…</ThemeContext>directamente; el formulario.Providerantiguo sigue funcionando pero registra una advertencia y está destinado a su eliminación. - Solo los Componentes de Servidor Pueden Ser async: Marca los componentes que cargan datos como Componentes de Servidor y usa
awaitdirectamente en el cuerpo — Los Componentes de Cliente no pueden ser async, no pueden usaruseState/useEffect, y no tienen acceso awindow,document, olocalStorage. - Pasa la Salida del Servidor a Través de children: Los Componentes de Cliente no pueden importar Componentes de Servidor (la importación se vuelve silenciosamente solo para cliente), así que compón pasando JSX del Componente de Servidor pre-renderizado a través de
childreno props JSX nombrados desde un padre Componente de Servidor. - Serializa Más que JSON: Los props que cruzan el límite Servidor→Cliente pueden ser
Date,Map,Set,FormData, arrays tipados, Promises sin esperar, y Acciones de Servidor — pero nunca funciones regulares, instancias de clase, o nodos DOM. - Marca Funciones, No Archivos:
"use server"convierte funciones async individuales en puntos finales RPC, así que evita ponerlo en la parte superior de un archivo de componente esperando que todas las exportaciones se conviertan en acciones — eso rompe las exportaciones del componente en su lugar. - Devuelve un Objeto de Resultado Desde Acciones: Lanzar dentro de una Acción de Servidor cruza el límite de la red y puede fallar el cliente; devuelve un resultado discriminado —
return { success: true, data }oreturn { success: false, error: "Invalid" }— y reservathrowpara fallos genuinamente inesperados capturados porerror.tsx. - Observa las Cargas de Cierre de Acción Incorporadas: Las variables capturadas por acciones incorporadas
"use server"se serializan como campos de formulario ocultos encriptados en cada renderizado, así que extrae los cierres pesados a archivos de acción de nivel superior cuando el estado capturado se vuelve grande. - Usa useFormStatus en un Hijo:
useFormStatus()solo refleja el ancestro<form>más cercano, así que llamarlo en el mismo componente que renderiza el formulario siempre devuelvepending: false— mueve el botón que lee el estado a un hijo del formulario. - useActionState Reemplaza el Estado Completamente: El valor de retorno de una acción sobrescribe completamente el estado (sin fusión de tipo reductor), así que expande el estado anterior explícitamente —
return { ...prevState, error: "Invalid email" }— y recuerda importarlo desde"react", no"react-dom". - Prefiere Entradas No Controladas en Formularios de Acción: Las entradas controladas pierden valores mecanografiados por el usuario cuando una acción re-renderiza el formulario desde el estado de error; las entradas no controladas (o mantener valores de entrada en el estado devuelto) preservan la entrada a través de errores de validación y los formularios no se reinician automáticamente en éxito.
- Nunca Crees Promesas En Render Con use: Crear una nueva promesa dentro del cuerpo del componente y pasarla a
use()causa un bucle infinito de Suspense; eleva la creación de promesas a un Componente de Servidor padre, un caché estable, o un prop para que la referencia sea estable a través de renderizados. - Empareja use Con Suspense y Error Boundary:
use(promise)requiere un ancestro Suspense para mostrar el estado de carga y un límite de error para capturar rechazos — sin ambos, la aplicación falla silenciosamente o cuelga en promesas pendientes. - Llama use Condicionalmente Cuando Necesites: A diferencia de los hooks,
use()es legal dentro deif, bucles, y retornos tempranos —if (shouldLoad) { const data = use(promise) }— aprovecha esto para lecturas de contexto condicionales y desenvueltas de promesas protegidas en lugar de forzar formas antiguas deuseContext/useEffect. - Llama addOptimistic Dentro de una Acción:
addOptimisticsilenciosamente no hace nada a menos que se invoque dentro de una acción de formulario, manejador de Acción de Servidor, o unstartTransitionexplícito; envuelve llamadas de manejador de eventos:startTransition(() => addOptimistic(newItem))para que la actualización optimista realmente se aplique. - Mantén updateFn Pura: La
updateFnpasada auseOptimisticdebe ser pura y producir un nuevo valor — mutar estado o referenciar alcance con efectos secundarios rompe la reversión automática en fallo. - Superficies de Errores Junto con Reversión Optimista: Cuando una acción fallida se revierte, la interfaz silenciosamente se revierte sin indicación; empareja
useOptimisticconuseActionStatepara que los errores aún se rendericen al usuario después de la reversión. - Desestructura ref Antes de Expandir: Los componentes funcionales ahora aceptan
refcomo un prop ordinario, así que{...props}accidentalmente reenvíarefjunto con todo lo demás — desestructúralo explícitamente:({ ref, ...props }) => <input ref={ref} {...props} />, especialmente cuando el componente es un paso a través. - Callbacks de Ref Devuelven Limpieza: Los callbacks de ref ahora pueden devolver una función de limpieza (como
useEffect); devolver cualquier otra cosa (no función, no indefinido) dispara una advertencia dev, así que devuelve una limpieza o no devuelvas nada en absoluto. - Dale a las Hojas de Estilo una precedencia:
<link rel="stylesheet" precedence="…">opta por la deduplicación, ordenamiento y Suspense-hasta-carga de React — sinprecedence, la hoja de estilo es no gestionada y puedes tener FOUC u hojas duplicadas. - Evita Múltiples Etiquetas title: React eleva
<title>a<head>pero solo la última renderizada gana, así que dispersar títulos a través de componentes produce resultados dependientes del orden; elige un único sitio de<title>(o usa la API de metadatos del framework) y apégate a ello. - preload Descargas, preinit Ejecuta: Usa
preloadcuando solo quieras los bytes en caché ypreinitcuando también quieras que scripts se ejecuten u hojas de estilo se apliquen;preinitejecuta scripts inmediatamente y falla si dependen de DOM que aún no se ha renderizado. - Precarga Fuentes Con crossOrigin Anonymous: La especificación de Fetch requiere
crossOrigin: "anonymous"en precarga de fuentes incluso para solicitudes del mismo origen —preload("/font.woff2", { as: "font", crossOrigin: "anonymous" })— sin ello el navegador descarga la fuente dos veces y la sugerencia de precarga se desperdicia. - Sigue las Reglas de React para el Compilador: El Compilador de React silenciosamente omite cualquier componente que mute props/state en render o haga efectos secundarios durante render — ningún error de compilación, solo sin memoización — así que trata "render puro" como una regla dura si quieres los beneficios del compilador.
- Ejecuta eslint-plugin-react-compiler: El plugin ESLint marca violaciones de reglas que el compilador silenciosamente omitirá; combínalo con
compilationMode: "annotation"y la directiva"use memo"para un despliegue gradual, y usa"use no memo"para opt out de funciones específicas.