Lista de verificación para la revisión del código React: mejora la seguridad y el rendimiento

Para aplicaciones React complejas, una auditoría de código y revisión de calidad por parte de terceros es mucho más que algo deseable: es una inversión fundamental. Saltarse este paso o realizar solo revisiones superficiales puede dar lugar a una cascada de problemas más adelante: incapacidad para escalar, vulnerabilidades de seguridad y deuda técnica que ahoga la innovación y dispara los costes de desarrollo.

Por eso hemos elaborado esta completa lista de verificación para la revisión del código React. En Redwerk, llevamos desde 2005 desarrollando software personalizado y realizando revisiones de código. Esta guía se basa en años de experiencia práctica en varios sectores, como la administración electrónica, el comercio electrónico, el aprendizaje electrónico, los medios de comunicación y el entretenimiento, entre otros.

Así que, tanto si te estás preparando para lanzar una aplicación basada en React, como si estás abordando problemas de rendimiento o pretendes prepararte de forma proactiva para la diligencia debida iniciada por un inversor, esta lista de verificación para la revisión del código React JS te ayudará a identificar problemas y encontrar soluciones.

Preparación previa a la revisión

La preparación previa a la revisión garantiza que el entorno esté listo, que las dependencias estén actualizadas y que el código base se encuentre en condiciones óptimas para una revisión eficiente y exhaustiva del código React. Este paso se centra en organizar el proyecto, establecer objetivos claros y garantizar que todas las herramientas, configuraciones y documentación estén disponibles para facilitar un proceso de revisión fluido.

Definir el alcance y los objetivos:

  • Describir claramente los objetivos y las áreas de interés de la revisión, como la calidad del código, el rendimiento, la seguridad o una funcionalidad específica (como una característica o un módulo concreto)
  • Determinar si la revisión abarcará toda la aplicación, componentes específicos o características clave
  • Establecer criterios medibles para el éxito, como mejorar la legibilidad del código, reducir los posibles errores u optimizar el rendimiento

Verificar la configuración del proyecto y las dependencias:

  • Asegúrese de que todas las dependencias estén actualizadas ejecutando npm install o yarn install. Además, confirme que no se estén utilizando paquetes obsoletos o vulnerables
  • Revise el archivo package.json para verificar su exactitud y evite paquetes innecesarios u obsoletos
  • Compruebe que el proyecto utilice la última versión estable de React y todas las bibliotecas relacionadas (por ejemplo, React Router, Redux, etc.), para garantizar la compatibilidad con las mejores prácticas modernas
  • Verifique que las bibliotecas de terceros estén configuradas correctamente y que su uso sea necesario

Confirme la configuración del entorno:

  • Asegúrese de que el entorno de desarrollo esté configurado correctamente con todas las herramientas necesarias, como ESLint para la depuración de código, Prettier para el formateo y cualquier otra extensión o depurador específico de React
  • Verifique que el proyecto se ejecuta correctamente tanto en el entorno de desarrollo como en el de producción, lo que incluye ejecutar la aplicación localmente (npm start, yarn start) y compilarla para producción (npm run build, yarn build) sin errores ni advertencias
  • Asegúrese de que cualquier configuración específica del entorno (por ejemplo, puntos finales de API, variables de entorno) se gestione correctamente utilizando archivos .env o herramientas de configuración, para evitar codificar valores directamente en el código base

Revisar y optimizar la cobertura de las pruebas:

  • Asegurarse de que se han realizado pruebas unitarias para todos los componentes y funciones críticos, utilizando bibliotecas de pruebas como Jest y React Testing Library
  • Asegurarse de que la cobertura de las pruebas es completa y abarca las interacciones clave de los usuarios, la gestión del estado y los casos extremos
  • Revisar la estructura del conjunto de pruebas para asegurarse de que están organizadas de forma lógica y no se solapan: las pruebas unitarias deben centrarse en funcionalidades aisladas, mientras que las pruebas de integración pueden verificar la interacción entre componentes
  • Verifique que el conjunto de pruebas se ejecuta sin errores ni fallos (npm test, yarn test) y que se realizan afirmaciones significativas
  • Asegúrese de que todas las pruebas sean descriptivas, utilizando nombres que expliquen claramente la funcionalidad que se está probando

Ejecutar herramientas de análisis de código estático:

  • Asegúrese de que las herramientas de análisis de código estático, como ESLint y Prettier, estén instaladas y configuradas correctamente para aplicar un estilo de código coherente e identificar posibles problemas, como variables no utilizadas, errores de sintaxis o código sospechoso
  • Ejecute las herramientas de análisis de código y revise los resultados antes de comenzar la revisión para abordar cualquier problema relacionado con el estilo o el linting
  • Asegúrese de que las reglas de buenas prácticas se apliquen de manera coherente en todo el proyecto
  • Verifique que los resultados del linting y el formateo del código se integren en el proceso de CI/CD para garantizar los estándares de calidad del código en cada solicitud de extracción o fusión de código

Compruebe y organice la documentación:

  • Asegúrese de que la documentación relevante del proyecto esté actualizada, incluyendo un README claro que describa cómo configurar, construir y ejecutar el proyecto, así como cualquier instrucción de configuración específica para los revisores
  • Verificar que se utilicen comentarios en línea y documentación del código (por ejemplo, JSDoc) cuando sea necesario para explicar la lógica compleja, los argumentos de las funciones o el comportamiento esperado, facilitando así la comprensión del código por parte de los revisores
  • Revisar cualquier documentación de la API o integraciones de servicios de terceros para garantizar que estén debidamente documentadas y sean accesibles para los revisores que puedan necesitar contexto adicional durante la revisión

Revisar el flujo de trabajo de Git y las ramas de código:

  • Asegurarse de que el proyecto siga un flujo de trabajo de Git bien definido (por ejemplo, Gitflow, ramificación de funciones) para mantener los cambios de código organizados y gestionables durante la revisión
  • Revisar las ramas de funciones para asegurarse de que se fusionan correctamente
  • Verificar que cualquier solicitud de extracción abierta o rama de funciones se rebase o se fusione con los últimos cambios de la rama principal, evitando conflictos o código obsoleto durante el proceso de revisión
  • Asegúrese de que se utilicen mensajes de confirmación significativos, que describan claramente el propósito de cada cambio

Valide las dependencias externas y las API:

  • Asegúrese de que todas las dependencias externas (por ejemplo, API, servicios de terceros) se simulen correctamente para fines de prueba y revisión
  • Asegúrese de que no haya dependencias estrictas de servicios externos que puedan romperse o fallar durante la revisión
  • Revisar la configuración de las llamadas a la API, asegurándose de que se gestiona el error en caso de solicitudes fallidas y de que los datos confidenciales, como las claves o los tokens de la API, se almacenan de forma segura utilizando variables de entorno
  • Verificar que las bibliotecas y API de terceros se utilizan de forma eficiente y considerar alternativas si la dependencia puede sustituirse por funciones integradas de React u opciones más ligeras

Configurar y probar el proceso de compilación y despliegue:

  • Asegúrese de que el proceso de CI/CD esté correctamente configurado para compilar, probar e implementar automáticamente la aplicación; esto incluye pruebas automatizadas, linting y análisis estático para detectar problemas de forma temprana
  • Revise la configuración de compilación (por ejemplo, Webpack, Vite) para asegurarse de que la compilación de producción esté optimizada para el rendimiento, con funciones como tree shaking y code splitting habilitadas
  • Verifique que el proceso de implementación funcione correctamente, implementando automáticamente los cambios en los entornos de staging o producción sin errores

Preparación de datos y escenarios de prueba:

  • Asegúrate de que los datos y los escenarios de prueba estén preparados para su revisión: conjuntos de datos de muestra o datos simulados para probar diferentes partes de la aplicación, como formularios, API e interacciones de los usuarios
  • Revisar y configurar casos de prueba realistas para los componentes clave, asegurándose de que cubren varios escenarios de entrada (por ejemplo, casos válidos, no válidos y extremos) y están bien documentados para que el revisor pueda seguirlos
  • Asegurarse de que los flujos de usuarios y el comportamiento funcional se pueden replicar fácilmente durante la revisión, para ayudar a los revisores a comprender cómo interactúa el código con el resto de la aplicación

Legibilidad y coherencia del código

Garantizar la legibilidad y la coherencia del código es fundamental para mantener una base de código React limpia y fácil de mantener. Un código legible y coherente permite una colaboración más fluida, una depuración más sencilla y una incorporación más rápida de nuevos desarrolladores. A continuación te explicamos cómo asegurarte de que tus desarrolladores de React JS han hecho un buen trabajo.

Sigue convenciones de nomenclatura coherentes:

  • Asegúrate de que los componentes, las funciones, las variables y los archivos sigan convenciones de nomenclatura coherentes y significativas (utiliza PascalCase para los nombres de los componentes React y camelCase para las funciones, las variables y los hooks)
  • Comprueba que los nombres de los archivos coincidan con el componente o la función que exportan; evita las abreviaturas o los nombres demasiado genéricos que oculten el propósito del código
  • Asegúrate de que los nombres de las variables de estado y los props sean coherentes y describan claramente los datos que representan (Por ejemplo, isLoading, userList)

Mantener firmas de componentes y funciones claras:

  • Asegúrate de que las firmas de funciones y componentes sean simples y autoexplicativas, con nombres de parámetros descriptivos
  • Asegúrate de que no haya firmas de funciones demasiado complejas con argumentos excesivos, mientras que los parámetros relacionados se agrupan en objetos si es necesario
  • Verifica que las propiedades pasadas a los componentes sean concisas, evitando propiedades innecesarias o redundantes que saturen la firma del componente
// Correct: uses clear and descriptive names
type UserCardProps = {
  username: string;
  age: number;
};

const UserCard: React.FC = ({ username, age }) => {
  return (
    

{username}

Age: {age}

); }; // Wrong: component name Card is too generic, prop names are unclear const Card = ({ u, a }) => { return (

{u}

Age: {a}

); }

Utiliza comentarios claros y descriptivos:

  • Asegúrate de que los comentarios se utilicen para explicar la lógica no obvia, especialmente en lo que respecta a las reglas de negocio o las transiciones de estado complejas
  • Comprueba que los comentarios sean claros y concisos, y que proporcionen un contexto valioso sin ser demasiado prolijos
  • Asegúrate de que expliquen el «porqué» de las decisiones, en lugar de limitarse a indicar lo que hace el código
  • Verifica que los comentarios en línea estén actualizados y sean relevantes para el código que describen
// Correct: explains  the purpose of the component
// Displays a user's profile information
const UserProfile = ({ name, age }: { name: string; age: number }) => (
  

{name}

Age: {age}

); // Wrong: the comment repeats what the code already shows // This is a UserProfile component const UserProfile = ({ name, age }) => (

{name}

Age: {age}

);

Consistent Use of JSX Syntax and Formatting:

  • Ensure that JSX syntax is consistent, including indentation, spacing, and the placement of attributes—use single-line JSX for short elements and multi-line JSX for elements with multiple props or children
  • Review that JSX is properly formatted with consistent use of self-closing tags for elements without children (e.g., instead of )
  • Ensure that props are aligned and indented in a consistent way, improving the readability of long JSX attributes
// Correct: uses consistent indentation and proper spacing
const UserProfile = ({ name, age }: { name: string; age: number }) => (
  

{name}

Age: {age}

); // Wrong: uses inconsistent indentation, making it harder to read const UserProfile = ({name,age}) =>

{name}

Age: {age}

;

Garantizar un formato y estilo coherentes en el código:

  • Asegúrese de que el código siga una guía de estilo coherente en todo el proyecto, utilizando herramientas de formato como Prettier para aplicar de forma coherente la sangría, el espaciado y los saltos de línea
  • Compruebe que la longitud de las líneas se mantenga dentro de un límite razonable (por ejemplo, entre 80 y 100 caracteres), lo que garantiza que el código siga siendo fácil de leer en diversos dispositivos o IDE
  • Verifique que se sigan de manera coherente las reglas de linting del proyecto (por ejemplo, ESLint) para evitar diferencias innecesarias o discrepancias de formato en el código base

Utilice Prop Types o TypeScript para la seguridad de tipos:

  • Asegúrese de que los tipos PropTypes o TypeScript se utilicen de manera coherente para definir los tipos de props esperados por los componentes, lo que evita errores de tiempo de ejecución y mejora la legibilidad del código
  • Compruebe que las definiciones de tipos sean claras y concisas, y que las estructuras de datos complejas o los objetos anidados estén definidos correctamente
  • Verifique que se hayan establecido los valores predeterminados para las propiedades opcionales, ya sea a través de defaultProps (para proyectos JavaScript) o del encadenamiento opcional y los valores predeterminados de TypeScript
// Correct: adding prop types if no TypeScript support 
import PropTypes from "prop-types";

const Button = ({ label, onClick }) => {
  return ;
};

Button.propTypes = {
  label: PropTypes.string.isRequired,
  onClick: PropTypes.func.isRequired,
};

// Correct: adding TypeScript interface for props (correct)
import PropTypes from "prop-types";

const Button = ({ label, onClick }) => {
  return ;
};
Button.propTypes = {
  label: PropTypes.string.isRequired,
  onClick: PropTypes.func.isRequired,
};

// Wrong: no prop types or TypeScript interface 
const Button = (props: any) => {
  return ;
};

Evite expresiones demasiado complejas en JSX:

  • Asegúrese de que las expresiones JSX sean sencillas y fáciles de seguir
  • Asegúrese de que no haya lógica compleja incrustada directamente en JSX, ya que esto puede reducir la legibilidad
  • Verifique si los cálculos o la lógica condicional se trasladan a funciones auxiliares o variables de estado cuando sea necesario
  • Revise el uso de la representación condicional (&&, ? :) para asegurarse de que no esté demasiado anidada o sea difícil de leer
  • Compruebe si las condiciones complejas se dividen en múltiples expresiones más pequeñas o funciones auxiliares
  • Verifique que los elementos repetidos (por ejemplo, la representación de listas con map) sean concisos y estén claramente estructurados
  • Verifique si las propiedades key se utilizan adecuadamente para garantizar que React pueda rastrear los elementos de la lista de manera eficiente
// Correct: moves complex logic out of JSX into a function
const getDiscountMessage = (price: number) => {
  return price > 100 ? "You get a discount!" : "No discount available.";
};

const Product = ({ price }: { price: number }) => (
  

{getDiscountMessage(price)}

); // Correct: stores ternary logic in a variable to improve readability const Product = ({ price }: { price: number }) => ( const discountMessage = price > 100 ? "You get a discount!" : "No discount available.";

{discountMessage}

); // Wrong: hard to read because of nested expressions inside JSX const Product = ({ price }) => (

{price > 100 ? "You get a discount!" : "No discount available."}

);

Evite el código redundante o muerto:

  • Asegúrese de eliminar cualquier código comentado o sin usar del código base
  • Revise la lógica condicional o los indicadores de funciones que puedan dejar código innecesario en las compilaciones de producción
  • Verifique que el código duplicado se refactorice en componentes reutilizables o funciones auxiliares, promoviendo la reutilización del código y reduciendo los gastos generales de mantenimiento

Maneje de manera consistente la desestructuración de props y estado:

  • Asegúrese de que la desestructuración se utilice de manera consistente al manejar props y estado, mejorando la legibilidad al reducir la necesidad de referencias repetidas (por ejemplo, props.user se convierte en { user })
  • Revise que la desestructuración se aplique en la parte superior del componente o del cuerpo de la función para mantener una estructura limpia y organizada
  • Asegúrese de que no haya desestructuración directamente dentro de JSX, lo que puede reducir la legibilidad
// Correct: destructure in function parameters
const UserProfile = ({ name, age, location }) => {
  return (
    

{name}

Age: {age}

Location: {location}

); }; // Wrong: access props without destructuring const UserProfile = (props) => { return (

{props.name}

Age: {props.age}

Location: {props.location}

); };

Estructura y reutilización de los componentes

Una parte crucial de la auditoría de calidad del código es garantizar que los componentes sean modulares, reutilizables y estén bien organizados. Esto es importante porque una arquitectura de componentes bien estructurada y reutilizable es clave para crear aplicaciones React escalables y fáciles de mantener. Durante la revisión del código React, centrarse en la estructura y la reutilización de los componentes ayuda a garantizar que la aplicación siga siendo fácil de ampliar.

Asegúrate de que los componentes sigan el principio de responsabilidad única:

  • Verifica que cada componente tenga una responsabilidad única y clara y que se centre en una sola funcionalidad
  • Asegúrate de que los componentes no sean responsables de demasiadas tareas (por ejemplo, renderizar la interfaz de usuario, gestionar una lógica de negocio compleja y manejar la obtención de datos en un solo lugar)
  • Revise los componentes grandes y refactorícelos en subcomponentes más pequeños si gestionan múltiples responsabilidades
  • Asegúrese de que la lógica empresarial esté separada de la representación de la interfaz de usuario
  • Asegúrese de que la lógica compleja sea gestionada por componentes contenedores o con estado, mientras que los componentes de presentación se centren únicamente en mostrar la interfaz de usuario
// Correct: keeps single responsibility and reusability
type UserCardProps = {
  name: string;
  age: number;
};

const UserCard: React.FC = ({ name, age }) => (
  

{name}

Age: {age}

); // Wrong: handles fetching data, loading state and complex rendering logic const UserCard = () => { const [user, setUser] = React.useState(null); React.useEffect(() => { fetch("/api/user") .then((res) => res.json()) .then((data) => setUser(data)); }, []); if (!user) return

Loading...

; return (

{user.name}

Age: {user.age}

); };

Promueva la reutilización con componentes genéricos:

  • Asegúrese de que los patrones comunes de la interfaz de usuario (por ejemplo, botones, modales, campos de formulario) estén encapsulados en componentes genéricos reutilizables que puedan utilizarse en diferentes partes de la aplicación
  • Revise los componentes en busca de duplicaciones y refactorice los fragmentos de código similares en componentes compartidos o funciones de utilidad
  • Verifique que no se recree una lógica similar en varios lugares
  • Verifique que los componentes estén diseñados teniendo en cuenta la flexibilidad, utilizando props para personalizar el comportamiento o la apariencia
// Correct: reusable for different cases
const Button = ({ label, onClick, variant = "primary", disabled = false }) => {
  return (
    
  );
};

// Usage
;
};

Utiliza una jerarquía y un anidamiento adecuados de los componentes:

  • Asegúrate de que los componentes estén estructurados en una jerarquía clara que refleje la estructura lógica de la aplicación
  • Asegúrate de que no haya un anidamiento profundo de los componentes, ya que esto puede dificultar el seguimiento y el mantenimiento del código
  • Revisa las relaciones entre los componentes padres e hijos para asegurarte de que los datos fluyan de forma natural desde los componentes padres a los hijos a través de los props
  • Asegúrese de que no haya un exceso de prop drilling (paso de props a través de múltiples capas) utilizando bibliotecas de gestión de contexto o estado cuando sea necesario
  • Verifique que los componentes reutilizables se coloquen en los directorios adecuados (por ejemplo, /components/shared para los componentes comunes) para mejorar la organización y la accesibilidad en todo el código base

Asegúrese de que haya una separación clara entre los componentes contenedores y los componentes de presentación:

  • Asegúrate de que la aplicación separe los componentes contenedores (que gestionan el estado, la lógica y la obtención de datos) de los componentes de presentación (que se centran en renderizar la interfaz de usuario)
  • Revisa los componentes de presentación para asegurarte de que no tienen estado y reciben todos los datos y acciones necesarios a través de props, lo que facilita su reutilización y prueba
  • Verifica que los componentes contenedores se encargan de gestionar el estado y obtener datos, mientras que las tareas de renderizado se delegan a los componentes de presentación

Utiliza la composición en lugar de la herencia:

  • Asegúrate de que los componentes se construyan utilizando la composición en lugar de la herencia, ya que React promueve un modelo de composición de componentes, en el que se combinan componentes más pequeños para construir interfaces de usuario más complejas
  • Revisa cómo se componen los componentes para asegurarte de que los bloques de construcción reutilizables (por ejemplo, envoltorios de diseño, elementos de la interfaz de usuario) se combinan de forma eficaz
  • Verifica que la propiedad children de React se utilice cuando sea apropiado para pasar JSX como contenido a los componentes, lo que permite una composición flexible sin necesidad de codificar la estructura dentro de los componentes
// Correct: composition with 'children' is more clear and easy to extend
const Card = ({ title, children }) => {
  return (
    

{title}

{children}
); }; // Usage

Name: Alice

Email: alice@example.com

; // Wrong: using inheritance instead of composition class Card extends React.Component { render() { return (

{this.props.title}

{this.renderContent()}
); } renderContent() { return null; // To be overridden by subclasses } } class UserProfileCard extends Card { renderContent() { return ( <>

Name: Alice

Email: alice@example.com

); } } // Usage ;

Evita el uso de estilos hardcoded, utiliza componentes con estilo o módulos CSS:

  • Asegúrate de que el estilo se aplique de forma coherente utilizando bibliotecas CSS-in-JS como Styled Components o Emotion, o utilizando módulos CSS para mantener los estilos dentro de un ámbito y facilitar su mantenimiento
  • Revisa el uso de estilos en línea y valores codificados en JSX para asegurarte de que se reducen al mínimo
  • Comprueba que los elementos reutilizables de la interfaz de usuario (por ejemplo, botones, entradas) tengan estilos coherentes en toda la aplicación, lo que mejora tanto el mantenimiento como la experiencia del usuario
// Correct: using styled components
import styled from "styled-components";

// Styled button with dynamic props
const Button = styled.button`
  background-color: ${(props) => (props.primary ? "blue" : "gray")};
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  
  &:hover {
    background-color: ${(props) => (props.primary ? "darkblue" : "darkgray")};
  }
`;

// Usage
const App = () => (
  <>
    
    
  
);

// Wrong: hardcoded inline styles
const Button = ({ primary, children }) => (
  
);

const App = () => (
  <>
    
    
  
);

Garantizar la accesibilidad en los componentes reutilizables:

  • Asegúrese de que los componentes reutilizables sean accesibles de forma predeterminada, siguiendo las mejores prácticas, como proporcionar atributos aria adecuados, etiquetas y compatibilidad con la navegación por teclado
  • Compruebe que los botones, los elementos de formulario y otros componentes interactivos incluyan los atributos necesarios para que sean accesibles para todos los usuarios (por ejemplo, aria-label, role, tabIndex)
  • Verifique que cualquier biblioteca de componentes reutilizables o sistema de diseño siga las normas de accesibilidad, garantizando que la aplicación sea inclusiva y cumpla con los requisitos de accesibilidad
// Correct: using aria labels & semantic elements
const IconButton = ({ icon, label, onClick }) => {
  return (
    
  );
};

// Wrong: missing aria and wrong elements
const IconButton = ({ icon, onClick }) => {
  return {icon};
};

// Correct: using label and id in forms
const TextInput = ({ label, id, ...props }) => {
  return (
    
); }; // Wrong: missing label association const TextInput = ({ placeholder }) => { return ; };

Uso adecuado de los hooks de React y la gestión del estado

El uso eficaz de los hooks de React y la gestión del estado garantiza que las aplicaciones React sigan siendo predecibles, fáciles de mantener y escalables. Los hooks son una parte fundamental del desarrollo moderno con React, y comprender cómo gestionar el estado adecuadamente garantiza un mejor rendimiento y un código más limpio.

Utiliza useState para el estado local de los componentes:

  • Asegúrate de que useState se utiliza correctamente para gestionar el estado local de los componentes
  • Comprueba si las variables de estado representan los datos mínimos necesarios, evitando estados innecesarios o redundantes
  • Revisa los nombres de las variables de estado y sus setters para asegurarte de que describen claramente los datos y las acciones que representan (por ejemplo, isModalOpen, setIsModalOpen)
  • Verifica que la lógica de estado compleja se abstraiga en funciones auxiliares o callbacks de actualización de estado (por ejemplo, setState(prevState => newState)), evitando el re-renderizado excesivo o la manipulación directa del estado
// Correct: using functional update for safety
const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(prevCount => prevCount + 1);
  };

  return ;
};

// Wrong: directly modifying state
const Counter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1); // Might cause stale state issues
  };

  return ;
};

// Correct: using immutable updates for objects
const UserProfile = () => {
  const [user, setUser] = useState({ name: "Alice", age: 25 });

  const updateAge = () => {
    setUser(prevUser => ({ ...prevUser, age: prevUser.age + 1 }));
  };

  return ;
};

// Wrong: mutating state directly
const UserProfile = () => {
  const [user, setUser] = useState({ name: "Alice", age: 25 });

  const updateAge = () => {
    user.age += 1; // Direct mutation!
    setUser(user); // React may not detect this change
  };

  return ;
};

Utiliza useEffect para los efectos secundarios:

  • Asegúrate de que useEffect se utiliza correctamente para efectos secundarios como la obtención de datos, las suscripciones o la interacción con servicios externos
  • Asegúrate de que no hay efectos secundarios directamente dentro de la lógica de renderizado
  • Revisa la matriz de dependencias de useEffect para asegurarte de que refleja con precisión las variables de las que depende el efecto (las dependencias incorrectas o faltantes pueden provocar bucles infinitos o estados obsoletos)
  • Verifica que las funciones de limpieza se utilicen dentro de useEffect cuando sea necesario, especialmente para suscripciones, escuchas de eventos o temporizadores, a fin de evitar fugas de memoria y comportamientos no deseados

Evita el uso excesivo de useEffect para el estado derivado:

  • Asegúrate de que useEffect no se utilice en exceso para derivar estados que se pueden calcular directamente en el cuerpo del componente; por ejemplo, los datos derivados de props o estados deben calcularse dentro del método de renderizado o utilizando memoización (useMemo), no dentro de useEffect
  • Revisa los componentes en los que se establece el estado dentro de useEffect y refactorízalos para calcular los datos derivados fuera de useEffect, a menos que la lógica dependa de datos asíncronos externos
// Correct: using useMemo for expensive computations
const ExpensiveComponent = ({ items }) => {
  const computedValue = useMemo(() => {
    console.log("Running expensive computation...");
    return items.reduce((sum, item) => sum + item.value, 0);
  }, [items]); // Only recalculates when `items` change

  return 

Computed Value: {computedValue}

; }; // Wrong: using useEffect to set state const ExpensiveComponent = ({ items }) => { const [computedValue, setComputedValue] = useState(0); useEffect(() => { console.log("Running expensive computation..."); setComputedValue(items.reduce((sum, item) => sum + item.value, 0)); }, [items]); // Unnecessary effect return

Computed Value: {computedValue}

; };

Utiliza useContext para compartir el estado global:

  • Asegúrate de que useContext se utiliza para compartir el estado global o de toda la aplicación, reduciendo la necesidad de propagar propiedades a través de múltiples componentes
  • Revisa el proveedor de contexto y asegúrate de que se utiliza en un nivel adecuado en el árbol de componentes para evitar re-renderizaciones innecesarias de los componentes secundarios
  • Verifica que el contexto se utiliza con moderación para datos verdaderamente globales (por ejemplo, autenticación, tema) y que el estado local se gestiona dentro de los componentes utilizando useState u otros hooks

Aprovecha useReducer para la lógica de estado compleja:

  • Asegúrate de que useReducer se utiliza para gestionar la lógica de estado compleja, especialmente cuando las transiciones de estado implican múltiples acciones o requieren actualizaciones estructuradas
  • Revisa la función reducer para asegurarte de que es pura, lo que significa que solo depende de su entrada y no causa efectos secundarios ni muta el estado directamente
  • Verifica que los tipos de acción y las cargas útiles estén claramente definidos y sean descriptivos, asegurándote de que la lógica del reducer siga siendo clara y comprensible

Utiliza useRef para valores mutables y manipulación del DOM:

  • Asegúrate de que useRef se utiliza para valores que deben persistir entre renderizaciones sin provocar nuevas renderizaciones (por ejemplo, elementos DOM, temporizadores o variables mutables)
  • Revisa el uso de useRef para la manipulación del DOM o la interacción con bibliotecas de terceros
  • Asegúrate de que la manipulación directa del DOM se reduzca al mínimo y de que se respete el modelo de renderizado de React
  • Verifica que useRef no se utilice incorrectamente para la gestión del estado; solo debe utilizarse en casos en los que los cambios en la referencia no necesiten provocar nuevos renderizados

Gestiona el estado asíncrono con un manejo adecuado de los errores:

  • Asegúrate de que las operaciones asíncronas (por ejemplo, llamadas a API, obtención de datos) dentro de useEffect u otros hooks se gestionen con un manejo de errores adecuado; utiliza bloques try-catch o .catch() para promesas a fin de evitar errores no detectados
  • Revisa que las variables de estado para los estados de carga, éxito o error (por ejemplo, isLoading, isError) se utilicen de forma coherente al gestionar el estado asíncrono, mejorando la experiencia del usuario durante las operaciones asíncronas
  • Verifique que las operaciones asincrónicas se cancelen cuando el componente se desmonta para evitar establecer el estado en componentes desmontados, lo que puede provocar fugas de memoria o errores

Organice el estado global con bibliotecas de gestión de contexto o estado:

  • Asegúrese de que el estado global (por ejemplo, autenticación, preferencias del usuario o configuración de temas) se gestione utilizando la API de contexto de React o bibliotecas de gestión de estado como Redux, Zustand o Recoil
  • Revise el uso de bibliotecas externas de gestión de estado para asegurarse de que son necesarias (para aplicaciones más sencillas, React Context y useReducer pueden ser suficientes sin introducir una complejidad innecesaria)
  • Verifique que la solución de gestión de estado global esté configurada con acciones, reductores o selectores claros para minimizar el código repetitivo y garantizar que la lógica del estado sea mantenible

Evite los errores comunes con los hooks de React:

  • Asegúrese de que los hooks se llaman en el orden correcto y solo dentro de componentes funcionales o hooks personalizados
  • Asegúrese de que los hooks de React no se llaman dentro de bucles, condicionales o funciones anidadas
  • Revise los hooks personalizados para asegurarse de que siguen las mejores prácticas y encapsulan la lógica reutilizable de forma eficaz
  • Verifique que los hooks personalizados devuelven valores y funciones que promueven un comportamiento coherente en toda la aplicación
  • Verifique que los hooks no se utilizan en exceso para gestionar estados locales simples o lógica que se puede manejar dentro del cuerpo del componente
  • Verifique si el uso de hooks es sencillo y necesario

Gestión de errores y casos límite

Una lista de verificación de React estaría incompleta sin una revisión exhaustiva de la gestión de errores y la gestión de casos límite. Estos son esenciales para crear aplicaciones React robustas que puedan gestionar con elegancia fallos inesperados y casos extremos.

Implementar límites de error para un manejo elegante de los errores:

  • Asegúrate de que los límites de error se implementen en los puntos adecuados del árbol de componentes para detectar errores de JavaScript en la interfaz de usuario y evitar que toda la aplicación se bloquee; utiliza componentDidCatch o crea componentes de límite de error con React.ErrorBoundary
  • Revise la ubicación de los límites de error para asegurarse de que cubren las secciones críticas de la interfaz de usuario (por ejemplo, alrededor de componentes grandes o complejos), pero sin abusar de ellos, ya que esto puede ocultar problemas más profundos en el código base
  • Verifique que los límites de error muestran una interfaz de usuario de respaldo significativa (por ejemplo, mensajes de error, opciones de reintento) para informar al usuario del problema sin revelar detalles técnicos

Gestione con elegancia los errores de API y de obtención de datos:

  • Asegúrate de que los errores de las llamadas a la API o de las operaciones de obtención de datos se gestionen correctamente utilizando bloques try-catch o .catch() para las promesas
  • Asegúrate de que no queden rechazos de promesas sin resolver o sin gestionar, ya que esto puede provocar errores de tiempo de ejecución
  • Revisa cómo se comunican a los usuarios los estados de error (por ejemplo, fallos de red, errores de API)
  • Asegúrate de que se muestren mensajes de error fáciles de entender en lugar de detalles técnicos del error
  • Verifique que los estados de error se gestionan utilizando variables de estado adecuadas (por ejemplo, isError, errorMessage) y asegúrese de que la interfaz de usuario ofrece opciones de respaldo o reintento en caso de que falle la obtención de datos

Anticipe y gestione los casos extremos:

  • Asegúrese de que la aplicación anticipa y gestiona los casos extremos comunes, como conjuntos de datos vacíos, valores nulos o indefinidos, o entradas de usuario que superan los límites esperados
  • Revise los componentes de renderización de listas para asegurarse de que gestionan situaciones en las que la matriz de datos está vacía o contiene elementos no válidos; proporcione una interfaz de usuario alternativa (por ejemplo, «No hay elementos disponibles») para estos casos
  • Verifique que los componentes del formulario gestionan casos extremos como valores de entrada excesivamente largos, formatos no válidos o entradas de usuario inesperadas; utilice lógica de validación para evitar que se envíen datos no válidos

Asegúrese de que se gestionan los errores en las operaciones asíncronas:

  • Asegúrese de que las operaciones asíncronas, como la obtención de datos con fetch, axios o GraphQL, estén envueltas en mecanismos de gestión de errores (por ejemplo, try-catch o .catch() para promesas) para evitar fallos silenciosos
  • Revise cómo se gestionan los estados de carga, éxito y error para las operaciones asíncronas. Asegúrese de que se proporcione la información adecuada a los usuarios (por ejemplo, indicadores de carga, mensajes de error, confirmaciones de éxito)
  • Verifique que las operaciones de larga duración o las solicitudes de red se gestionen correctamente, con un manejo de errores y una lógica de reintento adecuados para mejorar la experiencia del usuario en caso de problemas de red

Valide y desinfecte las entradas del usuario:

  • Asegúrese de que las entradas del usuario se validen correctamente tanto en el lado del cliente como en el del servidor para evitar que datos no válidos o inesperados causen problemas. Utilice bibliotecas de validación (por ejemplo, Yup, Formik) o lógica de validación personalizada para formularios complejos
  • Revise la lógica de validación de entradas para asegurarse de que cubre casos extremos comunes, como cadenas vacías, caracteres especiales y entradas excesivamente largas; proporcione mensajes de validación útiles para guiar a los usuarios
  • Verifique que las entradas de los usuarios se desinfectan para evitar posibles problemas de seguridad, como la inyección de scripts dañinos o caracteres no válidos en los formularios

Gestione los valores predeterminados y de reserva para los datos que faltan:

  • Asegúrese de que se proporcionen valores predeterminados cuando se acceda a datos potencialmente faltantes o indefinidos, especialmente cuando se trate de respuestas de API o propiedades opcionales
  • Revise el uso del encadenamiento opcional (?.) y los valores de parámetros predeterminados (||) para manejar con elegancia los valores indefinidos o nulos
  • Verifique que los componentes muestren contenido de respaldo adecuado cuando los datos estén faltantes o incompletos, evitando pantallas en blanco o errores de interfaz de usuario

Muestre mensajes de error significativos y fáciles de usar:

  • Asegúrese de que los mensajes de error que se muestran a los usuarios sean claros, concisos y útiles
  • Asegúrese de que no se muestren mensajes de error sin procesar de las respuestas de la API o del servidor, que pueden contener jerga técnica
  • Revise los mensajes de error en toda la aplicación para garantizar la coherencia en el tono y el estilo, y asegúrese de que guíen a los usuarios a tomar medidas correctivas (por ejemplo, «Inténtelo de nuevo» o «Póngase en contacto con el servicio de asistencia para obtener ayuda»)
  • Verifique que los errores críticos (por ejemplo, fallos en la obtención de datos, errores en el envío de formularios) incluyan opciones prácticas, como botones para volver a intentarlo o enlaces a páginas de asistencia

Implementar casos límite para las propiedades y el estado de los componentes:

  • Asegurarse de que los componentes manejen correctamente los valores de propiedad inesperados o incorrectos
  • Verificar si se utilizan PropTypes o TypeScript para aplicar los tipos y la estructura esperados de las propiedades pasadas a los componentes
  • Revisar los componentes para asegurarse de que manejan casos extremos, como propiedades que faltan o están incompletas
  • Utilizar propiedades predeterminadas o proporcionar lógica condicional para manejar estos casos sin romper el componente
  • Verificar que los componentes se renderizan correctamente cuando se les proporcionan varios casos límite en el estado, como matrices vacías, valores nulos o estados predeterminados

Utilizar técnicas de programación defensiva:

  • Asegurarse de que se utilizan técnicas de programación defensiva para evitar errores de tiempo de ejecución causados por entradas inesperadas, referencias nulas o datos no válidos (por ejemplo, comprobar si hay valores nulos o indefinidos antes de realizar operaciones con ellos)
  • Revise la lógica condicional para asegurarse de que maneja todos los casos extremos posibles, evitando que la aplicación entre en un estado inestable cuando se le proporcionan datos o entradas inesperadas
  • Verifique que los componentes se prueben en cuanto a su robustez, manejando varios casos extremos durante las fases de desarrollo y prueba para evitar fallos inesperados o excepciones no manejadas en producción

Evite los fallos silenciosos y registre los errores de forma eficaz:

  • Asegúrese de que los errores se registran de forma eficaz tanto en entornos de desarrollo como de producción
  • Asegúrese de que se utilizan herramientas de registro (por ejemplo, Sentry, LogRocket) para capturar información detallada sobre los errores sin exponerla al usuario final
  • Revise el código en busca de posibles fallos silenciosos, en los que se producen errores pero no se registran ni se comunican al usuario
  • Asegúrese de que los errores se detectan y se gestionan adecuadamente, con lógica de respaldo o mensajes de error
  • Verifique que los registros de errores estén estructurados e incluyan información relevante (por ejemplo, nombre del componente, seguimiento de la pila, acción del usuario) para facilitar la depuración en el futuro

Utilice límites de error adecuados para los componentes de terceros:

  • Asegúrese de que se apliquen límites de error en torno a los componentes o bibliotecas de terceros que puedan generar errores inesperados, especialmente cuando se integren con código complejo o desconocido
  • Revise cómo las bibliotecas de terceros gestionan los errores y asegúrese de que cualquier fallo se capture dentro de la aplicación
  • Cuando se gestionen errores internamente, asegúrese de que las bibliotecas externas no sean la única fuente de confianza

Optimización del rendimiento

React es increíblemente popular, ya que el 39,5 % de los desarrolladores de software de todo el mundo lo eligen como su marco web de referencia (solo superado por Node.js). Sin embargo, a medida que su aplicación crece en complejidad, es posible que note una disminución en su rendimiento, lo que puede afectar significativamente a la satisfacción del usuario. Por eso, el rendimiento de React es crucial para ofrecer una experiencia de usuario fluida.

Nuestros esfuerzos de optimización del rendimiento de React pueden centrarse en áreas clave como la reducción de las re-representaciones innecesarias de componentes, la minimización del tamaño de los paquetes de JavaScript y la mejora drástica de los tiempos de carga. Cuando realizamos una revisión del código, compartimos técnicas prácticas de optimización del rendimiento de React, identificando los cuellos de botella y las ineficiencias exactas que podrían estar frenando la capacidad de respuesta y la escalabilidad de su aplicación.

Utilice React.memo para la memorización de componentes:

  • Asegúrese de que los componentes que no necesitan volver a renderizarse con frecuencia estén envueltos en React.memo para evitar renderizaciones innecesarias
  • Revise los componentes que reciben los mismos props repetidamente para verificar si se puede aplicar React.memo, reduciendo el número de renderizaciones y mejorando el rendimiento en árboles de componentes grandes
  • Verifique que React.memo se utiliza de forma selectiva para los componentes en los que las re-renderizaciones son costosas
  • Asegúrese de que React.memo no se utiliza en exceso en componentes simples o ligeros en los que la optimización puede no ser necesaria

Utilice useMemo y useCallback para cálculos y funciones costosos:

  • Asegúrate de que useMemo se utiliza para memorizar cálculos costosos o datos derivados, evitando recálculos innecesarios en cada renderización
  • Revisa el uso de useCallback para memorizar funciones de devolución de llamada pasadas a componentes secundarios, evitando la recreación innecesaria de funciones que pueden provocar que los componentes secundarios se vuelvan a renderizar innecesariamente
  • Verifica que las matrices de dependencias para useMemo y useCallback sean correctas y cubran todas las variables que pueden desencadenar un recálculo

Evita las re-representaciones innecesarias:

  • Asegúrate de minimizar las re-representaciones de componentes comprobando si los valores de las propiedades o del estado han cambiado antes de actualizar el componente
  • Utiliza una lógica de comparación adecuada en el método del ciclo de vida shouldComponentUpdate (para componentes de clase) o utilizando hooks como React.memo y useCallback en componentes funcionales
  • Revise los componentes en busca de actualizaciones innecesarias de estado o propiedades que puedan desencadenar re-renderizaciones
  • Asegúrese de que solo se pasan datos relevantes como propiedades y de que no se actualiza el estado con los mismos valores
  • Verifique que no se pasan propiedades innecesarias (como propiedades no utilizadas o predeterminadas) a los componentes secundarios, lo que reduce la posibilidad de re-renderizaciones no deseadas

Implementar la carga diferida para la división de código:

  • Asegúrate de que la división de código se implemente utilizando React.lazy y Suspense para cargar los componentes bajo demanda, reduciendo el tamaño inicial del paquete y mejorando los tiempos de carga para los usuarios
  • Revisa las rutas y los componentes grandes para verificar que se carguen de forma diferida, especialmente los componentes que no son necesarios inmediatamente al cargar la página (por ejemplo, componentes para rutas o modales)
  • Verifique que se utilizan componentes de reserva de Suspense para mostrar los estados de carga mientras se recuperan los componentes cargados de forma diferida; asegúrese de que la interfaz de usuario de reserva sea clara y fácil de usar

Optimice las listas con React.Fragment y key Props:

  • Asegúrate de que las listas renderizadas con .map() incluyan una propiedad key única para cada elemento, a fin de ayudar a React a optimizar el proceso de reconciliación y evitar renderizaciones innecesarias
  • Comprueba que React.Fragment se utilice cuando sea necesario para agrupar elementos hermanos sin añadir nodos adicionales al DOM, especialmente en listas o renderizaciones condicionales
  • Verifica que el renderizado de la lista sea eficiente, evitando cálculos o renderizaciones innecesarios cuando los datos de la lista no hayan cambiado

Implementa el desplazamiento infinito o la paginación para conjuntos de datos grandes:

  • Asegúrate de que los conjuntos de datos grandes se gestionen de forma eficiente implementando la paginación o el desplazamiento infinito en lugar de cargar todos los datos a la vez
  • Comprueba que se utiliza la paginación o el desplazamiento infinito para las listas o tablas que muestran grandes cantidades de datos, asegurándote de que solo se renderizan un número limitado de elementos a la vez
  • Verifica que se aplican técnicas de carga diferida o desplazamiento virtual cuando sea apropiado para minimizar el número de elementos DOM renderizados a la vez

Utilice CSS-in-JS o división de código para los estilos:

  • Asegúrese de que los estilos se optimizan utilizando soluciones CSS-in-JS como Styled Components o Emotion, o dividiendo los archivos CSS para reducir el tamaño de los estilos cargados inicialmente
  • Compruebe que el CSS crítico se carga inicialmente, mientras que los estilos no esenciales se aplazan hasta que sean necesarios
  • Verifique que el estilo dinámico se maneje de manera eficiente, evitando estilos en línea o recalculando estilos en cada renderización, a menos que sea necesario

Minimice el tamaño del paquete JavaScript:

  • Asegúrese de que las bibliotecas innecesarias o no utilizadas se eliminen del proyecto para minimizar el tamaño del paquete JavaScript
  • Utilice herramientas como Webpack o Parcel para analizar y eliminar el código no utilizado
  • Revise el proyecto en busca de dependencias grandes que puedan sustituirse por alternativas más ligeras o implementaciones personalizadas para reducir el tamaño total del paquete
  • Verifique que los activos (por ejemplo, imágenes, fuentes) estén optimizados y que las bibliotecas grandes se dividan en fragmentos más pequeños utilizando importaciones dinámicas para dividir el código

Utilice useRef para evitar volver a renderizar datos mutables:

  • Asegúrese de que useRef se utilice para datos mutables que no necesitan activar volver a renderizar, como referencias DOM, temporizadores o interacciones API externas
  • Revise el uso de useRef para almacenar valores que persisten a lo largo de las representaciones sin provocar que el componente se vuelva a representar, como elementos de formulario o valores de animación
  • Verifique que useRef no se utilice para gestionar estados que deban activar actualizaciones de la interfaz de usuario, ya que puede provocar inconsistencias entre la interfaz de usuario y el estado de la aplicación

Optimice el rendimiento en formularios y el manejo de entradas:

  • Asegúrese de que las entradas de los formularios estén optimizadas utilizando controladores onChange que solo actualicen el estado cuando sea necesario
  • Asegúrese de que no se vuelva a renderizar todo el formulario con cada pulsación de tecla o interacción
  • Revise los componentes del formulario para asegurarse de que los componentes controlados no se vuelvan a renderizar innecesariamente ni activen actualizaciones; utilice técnicas como debouncing o useCallback para optimizar el manejo de entradas
  • Verifique que las validaciones de los formularios estén optimizadas utilizando bibliotecas como Formik o React Hook Form, que manejan el estado de los formularios de manera eficiente y evitan que se vuelvan a renderizar

Implementar Suspense para la obtención de datos:

  • Asegúrese de que Suspense se utilice para la obtención de datos en combinación con el modo concurrente de React para permitir un mejor rendimiento de renderizado, aplazando o suspendiendo el renderizado de los componentes hasta que los datos estén disponibles
  • Revise el uso de bibliotecas de obtención de datos (por ejemplo, SWR, React Query) que estén optimizadas para React y admitan el almacenamiento en caché, la revalidación y la obtención en segundo plano, minimizando la necesidad de solicitudes de datos redundantes
  • Verifique que los estados de carga se gestionen de forma eficaz con Suspense o con lógica personalizada, asegurándose de que la interfaz de usuario siga respondiendo mientras se esperan los datos

Optimizar imágenes y medios:

  • Asegúrese de que las imágenes y los archivos multimedia estén optimizados para el rendimiento utilizando técnicas como la carga diferida (loading=”lazy” para imágenes), tamaños de imagen adaptables y formatos WebP para reducir el tamaño de los archivos y el tiempo de carga
  • Compruebe que los archivos multimedia de gran tamaño (por ejemplo, vídeos) se aplacen o se carguen bajo demanda, reduciendo la carga inicial para los usuarios con conexiones lentas
  • Verifique que se utilizan herramientas como la compresión de imágenes o las redes de distribución de contenidos (CDN) para servir activos optimizados, mejorando los tiempos de carga y reduciendo el uso del ancho de banda

Perfil y benchmark del rendimiento:

  • Asegúrese de que se utilizan herramientas de perfilado del rendimiento (por ejemplo, React Profiler, Chrome DevTools) para identificar cuellos de botella, medir los tiempos de renderizado de los componentes y optimizar las áreas lentas de la aplicación
  • Revise los puntos de referencia de rendimiento para identificar qué componentes o partes de la aplicación están causando ralentizaciones, especialmente durante las interacciones de los usuarios o los ciclos de renderización complejos
  • Verifique que las técnicas de optimización (por ejemplo, memoización, carga diferida) se apliquen basándose en datos de rendimiento reales en lugar de en una optimización prematura, lo que garantiza mejoras significativas en el rendimiento

Prácticas recomendadas de seguridad

La seguridad de React no es negociable. Sus aplicaciones React manejan datos confidenciales de los usuarios, interactúan con diversas API y, en última instancia, operan en el entorno potencialmente inseguro del navegador de un usuario. Por ello, es absolutamente fundamental garantizar la correcta implementación de las mejores prácticas de seguridad de React. Al hacerlo, protege tanto su aplicación como a sus usuarios de una serie de vulnerabilidades, como el cross-site scripting (XSS), las fugas de datos insidiosas y muchos otros ciberataques comunes.

Cuando realizamos una revisión del código, nuestro análisis en profundidad de la seguridad de React JS garantiza que su aplicación no solo sea resistente a las amenazas, sino que también maneje todos los datos confidenciales con el máximo cuidado y seguridad.

Desinfecte las entradas de los usuarios para evitar ataques XSS:

  • Asegúrese de que todas las entradas de los usuarios se desinfecten antes de renderizarlas en la interfaz de usuario
  • Compruebe si se utilizan bibliotecas como DOMPurify para eliminar contenido potencialmente dañino, especialmente al renderizar HTML o contenido generado por el usuario
  • Revise los componentes para asegurarse de que se evitan métodos peligrosos como dangerouslySetInnerHTML, a menos que sea absolutamente necesario (si se utilizan, verifique que el contenido se desinfecta correctamente para evitar ataques XSS)
  • Verifique que las bibliotecas de terceros que manejan datos de usuario (por ejemplo, editores de texto enriquecido, bibliotecas de formularios) desinfectan correctamente el contenido antes de renderizarlo

Implemente una autenticación y autorización seguras:

  • Asegúrese de que los mecanismos de autenticación sean seguros, aprovechando estándares como OAuth2 o JSON Web Tokens (JWT) para gestionar la autenticación de los usuarios
  • Compruebe si los tokens se almacenan de forma segura utilizando cookies solo HTTP para evitar el acceso por parte del cliente
  • Revise los mecanismos de control de acceso para verificar que los componentes y las rutas estén protegidos en función del estado de autenticación y autorización del usuario
  • Compruebe si se utilizan PrivateRoute o técnicas equivalentes para proteger las rutas protegidas
  • Verifique que la información confidencial, como tokens JWT, claves API o credenciales de usuario, nunca se almacene en el almacenamiento local, el almacenamiento de sesión o directamente en el código JavaScript

Proteja contra la falsificación de solicitudes entre sitios (CSRF):

  • Asegúrese de que se implemente la protección CSRF, especialmente para operaciones que cambian el estado (por ejemplo, envíos de formularios, solicitudes API)
  • Compruebe si se utilizan tokens anti-CSRF que se validan en el lado del servidor
  • Revise cualquier componente de gestión de formularios o interacción con API para asegurarse de que utilizan encabezados y tokens seguros (por ejemplo, X-CSRF-Token) para protegerse contra ataques CSRF
  • Verifique que las solicitudes que modifican datos confidenciales requieren tokens CSRF válidos, asegurándose de que no se puedan procesar solicitudes no autorizadas

Utilice HTTPS y cookies seguras:

  • Asegúrese de que todas las comunicaciones entre el cliente y el servidor estén cifradas mediante HTTPS. Evite transmitir información confidencial (por ejemplo, tokens de autenticación, claves API) a través de conexiones HTTP no seguras
  • Revise la configuración de las cookies para asegurarse de que se utilizan cookies seguras, solo HTTP, para almacenar tokens de autenticación e información de sesión, lo que impide el acceso a través de JavaScript
  • Verifique que el atributo SameSite esté configurado en las cookies para evitar el acceso a cookies de origen cruzado y reducir el riesgo de ataques CSRF

Evite la exposición de datos confidenciales:

  • Asegúrese de que los datos confidenciales (por ejemplo, contraseñas, números de tarjetas de crédito) nunca se registren ni se expongan en las herramientas de desarrollo del navegador
  • Verifique que no se registre información confidencial en la consola ni se envíe en mensajes de error
  • Revise las solicitudes y respuestas de la API para asegurarse de que no se devuelvan datos confidenciales en las respuestas
  • Verifique que datos como contraseñas de usuario, tokens o información de identificación personal (PII) nunca se envíen al cliente
  • Verifique que el almacenamiento del lado del cliente (por ejemplo, almacenamiento local, almacenamiento de sesión) no contenga información confidencial como tokens JWT o credenciales de usuario

Implemente la Política de seguridad de contenido (CSP):

  • Asegúrese de que se implemente una política de seguridad de contenidos (CSP) para evitar la ejecución de scripts o recursos no autorizados (ayuda a mitigar los ataques XSS y de inyección de datos al restringir el contenido que se puede cargar en una página)
  • Revise la configuración de la CSP para asegurarse de que solo se permiten fuentes de confianza (por ejemplo, propias, CDN aprobadas) para cargar scripts, estilos y otros activos
  • Asegúrese de que no se utilicen directivas unsafe-inline o unsafe-eval
  • Verifique que los scripts o estilos inline necesarios se minimicen y se gestionen adecuadamente mediante la CSP, asegurándose de que no introduzcan vulnerabilidades de seguridad

Prevenir ataques de clickjacking:

  • Asegúrese de que el encabezado X-Frame-Options esté configurado en DENY o SAMEORIGIN para evitar que la aplicación se incruste en iframes de otros sitios
  • Revisar cualquier uso legítimo de iframes (por ejemplo, la incrustación de contenido de terceros) para garantizar que se mitiguen los riesgos de seguridad y que los iframes se utilicen de forma segura
  • Verificar que cualquier contenido incrustado, especialmente el procedente de fuentes de terceros, sea fiable y esté debidamente protegido

Validar los datos de las API y las fuentes externas:

  • Asegúrese de que los datos obtenidos de API o fuentes externas se validen correctamente antes de procesarlos o mostrarlos en la interfaz de usuario
  • Revise las llamadas a la API y verifique que la validación del lado del cliente se complemente con la validación del lado del servidor, asegurándose de que los datos proporcionados por el usuario se limpien y validen en el servidor
  • Verifique que se compruebe la integridad y la estructura de los datos entrantes (por ejemplo, validando esquemas JSON), evitando que se utilicen datos malformados o maliciosos en la aplicación

Utilice la limitación de velocidad y la restricción para las solicitudes de API:

  • Asegúrese de que se hayan implementado mecanismos de limitación de velocidad y restricción para evitar el abuso de las API, como ataques de fuerza bruta o ataques de denegación de servicio (DoS)
  • Compruebe si estas medidas de seguridad se han implementado en el lado del servidor para limitar el número de solicitudes que un cliente puede realizar en un tiempo determinado
  • Revise la interacción de la aplicación con las API para asegurarse de que se respeten las restricciones de solicitudes o los límites de velocidad
  • Verifique que no haya llamadas API frecuentes e innecesarias que puedan dar lugar a un uso excesivo de los recursos
  • Verifique que las API externas que se consumen cuenten con protecciones adecuadas de limitación de velocidad y que se haya implementado el manejo de errores para las respuestas con limitación de velocidad

Utilice un manejo de errores adecuado sin exponer información interna:

  • Asegúrese de que los mensajes de error que se muestran a los usuarios sean genéricos y no revelen información interna, como trazas de pila, rutas de servidor o detalles de la base de datos
  • Revise el manejo de errores en toda la aplicación para asegurarse de que los errores internos se registren en el lado del servidor, pero no se expongan al cliente
  • Verifique que la información confidencial se elimine de las respuestas de error antes de enviarlas al cliente, asegurándose de que los posibles atacantes no puedan recopilar detalles sobre el sistema

Supervise y registre los eventos relacionados con la seguridad:

  • Asegúrese de que los eventos de seguridad importantes, como los intentos fallidos de inicio de sesión, los intentos de acceso no autorizados y las violaciones de datos, se registren para su análisis y respuesta futuros
  • Compruebe si se utiliza una herramienta de registro como Sentry o LogRocket para capturar y notificar incidentes relacionados con la seguridad
  • Revise las configuraciones de registro para asegurarse de que los registros de seguridad se almacenan de forma segura y solo son accesibles para el personal autorizado
  • Verifique que no se registran datos confidenciales en texto sin formato
  • Verifique que se dispone de sistemas de registro y supervisión para detectar y responder a posibles amenazas de seguridad en tiempo real

Mejora la calidad de tu aplicación React con Redwerk

En Redwerk, hemos entregado con éxito más de 250 proyectos a empresas de Norteamérica, Europa, África, Australia y Nueva Zelanda. Apoyamos a nuestros clientes en cada etapa del ciclo de vida del desarrollo de software, ayudándoles a eliminar la deuda técnica, adoptar prácticas de codificación saludables e implementar flujos de trabajo probados que aumentan la frecuencia y la fiabilidad de los lanzamientos de software. Estos son solo algunos de los proyectos de React JS que se han beneficiado de nuestra experiencia.

Aceleración de la entrega de funciones para Orderstep

Cliente: Orderstep, un proveedor danés de SaaS para la gestión de presupuestos.

Limitaciones: un pequeño equipo interno que se enfrentaba a solicitudes de funciones pendientes de usuarios premium.

Solución: Redwerk intervino para ayudar a entregar a tiempo las capacidades prometidas desde hacía tiempo a los usuarios. Dado que el backend de la tienda web ya estaba completo, hacer que un marco tradicional fuera compatible con el frontend habría requerido muchos ajustes. Para combinar las ventajas de una aplicación de página única (SPA) con su configuración existente, integramos estratégicamente React para las partes interactivas de la tienda online, dejando las páginas estáticas independientes del marco.

Resultado: El desarrollo oportuno de la función de la tienda web para los usuarios premium aumentó significativamente los ingresos por suscripción.

Actualización rápida del módulo para Cakemail

Cliente: Cakemail, una empresa canadiense en expansión especializada en herramientas de marketing por correo electrónico.

Limitaciones: Un plazo ajustado y la necesidad urgente de actualizar un módulo crítico de la aplicación.

Solución: Preparamos completamente el frontend de la sección Formularios para una integración perfecta en la nueva versión de la aplicación Cakemail. Nuestra ayuda permitió a Cakemail completar la transición de Cakemail v4 a Cakemail v5 sin comprometer la funcionalidad de la aplicación.

Resultado: El módulo del formulario de suscripción se refactorizó con éxito en menos de 90 días, lo que permitió a Cakemail implementar la versión actualizada de la aplicación según lo previsto.

Reestructuración y lanzamiento de la plataforma para Evolv

Cliente: Evolv, una plataforma de optimización de la experiencia basada en la inteligencia artificial con sede en Estados Unidos.

Limitaciones: La presión para ofrecer nuevas funciones para el crecimiento de la base de usuarios, combinada con el extenso trabajo de reestructuración necesario tras la escisión de Sentient Technologies, sobrecargaba al equipo interno.

Solución: Se contrató a Redwerk para desarrollar el producto principal de Evolv: una plataforma de optimización pionera que comprende un editor web y un gestor. El editor web es la aplicación de escritorio de Evolv que permite codificar mejoras en la experiencia de usuario sin acceder directamente al código fuente del cliente, así como previsualizar, editar y probar los cambios implementados. El gestor es la plataforma web de Evolv, que cuenta con ajustes de prueba avanzados para lanzar experimentos. También continuamos manteniendo la plataforma.

Resultado: Transformamos la oferta heredada, Sentient Ascend, en la solución de crecimiento digital basada en IA número uno. Junto con el equipo de entrega de Redwerk, Evolv lanzó con éxito su nuevo producto, Evolv 1.0, que ahora utilizan numerosos clientes de Evolv.

Tanto si desea contratar desarrolladores de React JS para ampliar su equipo interno como si necesita la ayuda de expertos para una revisión imparcial del código React, estaremos encantados de ayudarle. Póngase en contacto con nosotros hoy mismo para compartir sus necesidades y obtener una visión clara de cómo podemos satisfacerlas, incluyendo un presupuesto gratuito para su proyecto.