window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versión: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster ya existe') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Visibilidad de componentes en React con renderizado condicional y protecciones - The Codest
The Codest
  • Quiénes somos
  • Servicios
    • Desarrollo de software
      • Desarrollo Frontend
      • Desarrollo backend
    • Staff Augmentation
      • Desarrolladores frontales
      • Desarrolladores de backend
      • Ingenieros de datos
      • Ingenieros de la nube
      • Ingenieros de control de calidad
      • Otros
    • Asesoramiento
      • Auditoría y consultoría
  • Industrias
    • Fintech y Banca
    • E-commerce
    • Adtech
    • Tecnología sanitaria
    • Fabricación
    • Logística
    • Automoción
    • IOT
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • Nuestro equipo
  • Case Studies
  • Saber cómo
    • Blog
    • Meetups
    • Seminarios en línea
    • Recursos
Carreras profesionales Póngase en contacto
  • Quiénes somos
  • Servicios
    • Desarrollo de software
      • Desarrollo Frontend
      • Desarrollo backend
    • Staff Augmentation
      • Desarrolladores frontales
      • Desarrolladores de backend
      • Ingenieros de datos
      • Ingenieros de la nube
      • Ingenieros de control de calidad
      • Otros
    • Asesoramiento
      • Auditoría y consultoría
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • Nuestro equipo
  • Case Studies
  • Saber cómo
    • Blog
    • Meetups
    • Seminarios en línea
    • Recursos
Carreras profesionales Póngase en contacto
Flecha atrás VOLVER
2023-05-19
Desarrollo de software

Visibilidad de componentes en React con renderizado condicional y guardias

Bartlomiej Kuczynski

Aprenda a simplificar y mejorar la visibilidad de los componentes en React utilizando la renderización condicional y los componentes de guardia.

Hoy me gustaría hablar de cómo controlar visibilidad de los componentes en React. Pero antes de empezar hay pequeñas
descargo de responsabilidad:

La solución presentada no es muy segura en el sentido de proteger su aplicación contra los "hackers" (quienesquiera que sean).
Recuerde que necesita proteger sus puntos finales y utilizar buenas prácticas en el diseño de aplicaciones. Esta solución sólo
hace su trabajo un poco más fácil.

Tarea, solución del problema o lo que nos gustaría conseguir

Una de las funcionalidades más comunes es mostrar el componente sólo para un grupo de usuarios que tienen algunos derechos específicos,
roles o privilegios. La solución habitual es añadir sis a código, comprobar manualmente las condiciones y mostrar o no los elementos.

Echemos un vistazo a SimpleAppHeader que contiene pocos elementos de navegación.

<!-- wp:paragraph -->
<p><code>typescript jsx<br>
export const SimpleAppHeader: FC = () =&gt; {<br>
    return (<br>
        <br>
            <nav><br>
                <ul><br>
                    {<br>
                        currentUser.role === "ADMIN" &amp;&amp;<br>
                        <li>Componente sólo para administradores</li><br>
                    }<br>
                    {<br>
                        currentUser.role === "USER" &amp;&amp;<br>
                        <li>Componente sólo usuario</li><br>
                    }<br>
                    {<br>
                        (currentUser.role === "ADMIN" || currentUser.role === "USER") &amp;&amp;<br>
                        <li>Componente sólo para administradores y usuarios</li><br>
                    <br>
                    <li>Elemento de uso general</li><br>
                </ul><br>
            </nav><br>
        </header><br>
    )<br>
}<br>
</code></p>
<!-- /wp:paragraph -->

No está mal. Probablemente se podrían encapsular las comprobaciones en funciones para reducir la complejidad. usuarioactual es algún objeto
que tiene papel pero puede ser cualquier cosa que queramos utilizar como objeto de nuestro mecanismo de control.

Este código tiene algunos problemas. Si proyecto crece probablemente utilizamos esas construcciones en muchos lugares. Así que tenemos que copiar,
de alguna manera, las condiciones. Este código es difícil de mantener y cambiar en el futuro. Especialmente cuando las reglas de acceso cambian durante
tiempo p. ej. tenemos que cambiar usuarioactual en otra cosa. Es muy difícil de probar. Tienes que escribir muchas pruebas
sólo para verificar si su estado es correcto.

Simplificación

Es hora de simplificar un poco este código. Podríamos extraer algunos métodos y hacer el código más corto y menos complejo:

const isAdmin = (rol: cadena): booleano => rol === "ADMIN";
const isUser = (rol: string): booleano => rol === "USUARIO";
const isAdminOrUser = (función: cadena): booleano => isAdmin(función) || isUser(función);

export const SimplifiedAppHeader: FC = () => {
return (

{

isAdmin(rolUsuarioactual) &&
Componente sólo admin

}
{
isUser(rolUsuarioactual) &&

Componente sólo usuario

}
{
(isAdminOrUser(rolUsuarioactual)) &&

Componente sólo Admin y Usuario

}

Elemento de uso general

)
}
```

Parece prometedor. Reducimos el ruido de las líneas repetidas. El código es más legible y fácil de mantener. Pero eche un vistazo a
función isAdminOrUser. Sólo tenemos dos funciones. Si introducimos un tercer rol necesitamos crear otro conjunto de funciones
que combina papeles. Hora de otra versión.

Filtrado

Introduzcamos la función hasRole que será el reemplazo de nuestro isX funciones.

const hasRole = (rol: string, requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => rol === s);
return encontrado !== indefinido;
}

export const FilteringAppHeader: FC = () => {
return (

{

hasRole(usuarioactual.role, ["ADMIN"]) &&
Componente sólo para administradores

}
{
hasRole(rolUsuarioactual, ["USUARIO"]) &&

Componente sólo usuario

}
{
hasRole(usuarioactual.role, ["ADMIN", "USUARIO"]) &&

Componente sólo para administradores y usuarios

}

Elemento de uso general

)
}
```

Ahora se ve bien. Todavía tenemos condiciones en la parte html del código, pero ahora podemos probar hasRole función y confiar en que
se utilizará con el conjunto correcto de parámetros. Añadir o cambiar roles es ahora más fácil. Usamos un array que contiene todos los
funciones que necesitamos.

Sin embargo, esta solución se une a usuarioactual objeto. Se supone que el objeto es de alguna manera global o de fácil acceso en
cualquier lugar de la aplicación. Así que podemos tratar de encapsular esto. Por supuesto, podemos moverlo a hasRole función:

 const hasRole = (requiredRole: string[]): boolean => {
     let found: string | undefined = requiredRole.find(s => currentUser.role === s);
     return found !== undefined;
 }

Pero eso no nos da casi nada.

En Guardia Componente

Es hora de crear un componente que encapsule toda la lógica. Lo llamé Guardia y así es como quiero usarlo.

 export const GuardedAppHeader: FC = () => {
     return (
         
             
  • Componente sólo para administradores
  • .
  • Componente sólo para usuarios
  • <li
  • Componente de administrador y usuario
  • Elemento de uso general
  • .
); }

El componente necesita dos propiedades. En primer lugar niños responsable de los contenidos vigilados. Segundo requiredRoles que
manejar el conjunto de roles que nos da acceso.

Necesitamos una representación de esta estructura. Es muy sencillo. Extendemos el tipo React.AtrezzoConNiños que tiene niños
propiedad. Por supuesto, puede añadir manualmente esa propiedad a su tipo y omitir la extensión.

interface IGuardProps extends React.PropsWithChildren {
requiredRoles: cadena[];
}

El componente en sí también es sencillo. Reutilizaremos hasRole función aquí.

export const Guard = (props: IGuardProps) => {
const hasRole = (requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => currentUser.role === s);
return encontrado !== indefinido;
}

if (hasRole(props.requiredRoles)) {
    return (
        
            {props.children}
        
    );
} else {
    return ;
}
}
"`

Y podría decir basta aquí, pero sería demasiado fácil. Ahora tenemos componente, y podemos usarlo hasta el extremo 😀 .

Servicio de guardia

El primer paso será la externalización de los controles. usuarioactual es un valor codificado. Me gustaría encapsular este valor
en algún servicio, que "sabrá" cómo verificar los roles. Técnicamente eso significa que movemos hasRole a otra función
clase.

Creo una interfaz sencilla IGuardService que sólo tiene una propiedad - hasRole.

exportar interfaz IGuardService {
checkRole: (roles: string[]) => boolean;
}

Una aplicación sencilla podría ser la siguiente

class SimpleGuard implements IGuardService {
checkRole(roles: cadena[]): booleano {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}

Para utilizarlo debemos cambiar IGuardProperties y caso de uso.

export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: cadena[];
guardService: IGuardService;
}

// ...

const AppHeader: FC = () => {
const guardService = nuevo SimpleGuard();
return (

Componente sólo para administradores
 

Componente sólo usuario

Componente Admin y Usuario
 
 

Elemento de uso general

 

);
}
```

Ahora el componente parece:

 export const Guard = (props: IGuardProps) => {
     if (props.guardService.checkRole(props.requiredRoles)) {
         return (
             
                 {props.children}
             
         );
     } else {
         return ;
     }
 }
 

Mucho mejor. Servicio de Guardia nos separan de la lógica que controla los papeles. Podemos cambiarlo sin consecuencias para nuestro
componente. El caso de uso común es utilizar un simulacro en las pruebas y una implementación "real" en el código de producción.

Elemento prohibido

La próxima mejora será la gestión de los Prohibido elemento. La solución actual muestra un elemento vacío. Primero necesitamos
cambiar IGuardProps función de adición que se renderizará ese elemento.

 export interface IGuardProps extends React.PropsWithChildren {
     requiredRoles: cadena[];
     guardService: IGuardService;
     ¿prohibido?: () => React.ReactNode;
 }

Esta propiedad es opcional, el nombre termina con un signo de interrogación. Así que podría ser función o indefinido. Necesitamos
manejarlo en Guardia componente.

export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (

{props.children}

);
} else if (props.forbidden === undefined) {
return ;
} else {
return (
{props.forbidden()}

);
}
}

// ...

export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
return (

Componente sólo para administradores
 

Componente sólo usuario

Prohibido - sólo moderador puede ver esto
}>
 

Componente moderador

 

Componente administrador y usuario
 
 

Elemento de uso general

 

);
}
```

Flexibilidad de tipos

Es hora del último gran cambio. El componente de la versión actual sólo admite roles como cadena. Podríamos tener múltiples
tipos de propiedad que nos gustaría comprobar. Números o tipos personalizados no es nada especial. Añadiré soporte para genéricos.

El primer paso son los cambios en IGuardService interfaz. Las implementaciones dependerán del tipo de valor comprobado. Puede ser
ser cualquier cosa, por lo que la interfaz debe manejarlo.

 exportar interfaz IGuardService {
     checkRole: (roles: ROLE[]) => boolean;
 }

Ahora toma array de PAPEL tipo genérico. Nuestra implementación simple cambiará un poco.

 class SimpleGuard implements IGuardService {
     checkRole(roles: string[]): boolean {
         let found: string | undefined = roles.find(e => e === currentUser.role);
         return found !== undefined;
     }
 }

Necesitamos añadir un parámetro de tipo, pero podríamos preparar una implementación que admita IRole interfaz.

interfaz IRole {
nombre: cadena;
}

//...
class RoleGuardService implements IGuardService {
checkRole(roles: IRole[]): boolean {
let encontrado: IRole | undefined = roles.find(e => e === userWithRole.role);
return encontrado !== indefinido;
}
}
```

El segundo paso es propagar este cambio a IGuardProps.

 interface IGuardProps extends React.PropsWithChildren {
     requiredRoles: ROLE[];
     guardService: IGuardService;
     ¿prohibido?: () => React.ReactNode;
 }

Y respectivamente a Guardia componente.

export const Guard = (props: IGuardProps) => {
     if (props.guardService.checkRole(props.requiredRoles)) {
         return (
             
                 {props.children}
             
         );
     } else if (props.forbidden === undefined) {
         return ;
     } else {
         return (
                 {props.forbidden()}
             
         );
     }
 }

Y nuestros casos de uso

export const AppHeader: FC = () =&gt; {
     const guardService = nuevo SimpleGuard();
     const roleService = nuevo RoleGuardService();
     return (
         <header>
             <nav>
                 <ul>
                     <Guard<IRole&gt; requiredRoles={[{name: "ADMIN"}]} guardService={roleService}&gt;
                         <li>Componente sólo para administradores</li>
                     </Guard>
                     <Guard<string&gt; requiredRoles={["USER"]} guardService={guardService}&gt;
                         <li>Componente sólo para usuarios</li>
                     </Guard>
                     <Guard<string&gt; requiredRoles={["MODERADOR"]} guardService={guardService}
                                    forbidden={() =&gt; <div>Prohibido - sólo moderador puede ver esto</div>}>
                         <li>Componente moderador</li>
                     </Guard>
                     <Guard<string&gt; requiredRoles={["USER", "ADMIN"]} guardService={guardService}&gt;
                         <li>Componente Admin y Usuario</li>
                     </Guard>
                     <li>Elemento de uso general</li>
                 </ul>
             </nav>
         </header>
     );
 }

En este ejemplo utilizo ambas implementaciones de IGuardservice sólo con fines ilustrativos. En casos reales
probablemente utilice sólo uno.

Componentes especializados y anidamiento

En Guardia pueden anidarse. Sólo recuerde que el acceso se resolverá en orden desde la instancia más externa.

export const NestAppHeader: FC = () =&gt; {
     const guardService = nuevo SimpleGuard();
     return (
         <header>
             <nav>
                 <ul>
                     <Guard<string&gt; requiredRoles={["USER", "ADMIN"]} guardService={guardService}&gt;
                         <Guard<string&gt; requiredRoles={["ADMIN"]} guardService={guardService}&gt;
                             <li>Componente sólo para administradores</li>
                         </Guard>
                         <Guard<string&gt; requiredRoles={["USER"]} guardService={guardService}&gt;
                             <li>Componente sólo para usuarios</li>
                         </Guard>
                         <li>Componente Admin y Usuario</li>
                         <Guard<string&gt; requiredRoles={["MODERADOR"]} guardService={guardService}
                                        forbidden={() =&gt; <div>Prohibido - sólo moderador puede ver esto</div>}>
                             <li>Componente moderador</li>
                         </Guard>
                     </Guard>
                     <li>Elemento de uso general</li>
                 </ul>
             </nav>
         </header>
     );
 }

En el ejemplo anterior Componente moderador nunca podría aparecer, porque el usuario sólo puede manejar un rol. Primero Guardia límites
funciones a ADMIN y USUARIOAsí que MODERADOR nunca pasará el primer control.

Podemos construir componentes especializados que oculten algunas propiedades.

export const AdminGuard = (props: Omit) => {
return 
{props.children}

}

//...
export const SpecializedAppHeader: FC = () => {
const guardService = new SimpleGuard();
return (

Componente sólo para administradores
 


Componente sólo para usuarios


Prohibido - sólo moderador puede ver esto
}>

Componente moderador



Componente de administrador y usuario

 

Elemento de uso general

);
}
```

En este caso AdminGuard predefinir ADMIN papel. En consecuencia, necesitamos definir explícitamente el tipo de PAPEL tipo
parámetro.

Resumen

En este artículo te muestro cómo crear y utilizar Guardia componente en React. Partimos de un código complejo y difícil de
leer y mantener. Lo convertimos en un estado más fácil de desarrollar e introducimos componentes funcionales personalizados. A continuación
ampliar el componente añadiendo funcionalidades adicionales, refactorizar el servicio de extracción y, por último, añadir tipos genéricos.

Por último, tenemos componente que se puede anidar es fácil de probar y mantener.

Artículos relacionados

Desarrollo de software

Ventajas e inconvenientes del React

¿Por qué merece la pena utilizar React? ¿Qué ventajas tiene esta librería JavaScript? Para conocer las respuestas sumérjase en este artículo y descubra las ventajas reales de utilizar React.

The Codest
Cezary Goralski Software Engineer

Suscríbase a nuestra base de conocimientos y manténgase al día de la experiencia del sector informático.

    Quiénes somos

    The Codest - Empresa internacional de desarrollo de software con centros tecnológicos en Polonia.

    Reino Unido - Sede central

    • Oficina 303B, 182-184 High Street North E6 2JA
      Londres, Inglaterra

    Polonia - Centros tecnológicos locales

    • Parque de oficinas Fabryczna, Aleja
      Pokoju 18, 31-564 Cracovia
    • Embajada del Cerebro, Konstruktorska
      11, 02-673 Varsovia, Polonia

      The Codest

    • Inicio
    • Quiénes somos
    • Servicios
    • Case Studies
    • Saber cómo
    • Carreras profesionales
    • Diccionario

      Servicios

    • Asesoramiento
    • Desarrollo de software
    • Desarrollo backend
    • Desarrollo Frontend
    • Staff Augmentation
    • Desarrolladores de backend
    • Ingenieros de la nube
    • Ingenieros de datos
    • Otros
    • Ingenieros de control de calidad

      Recursos

    • Hechos y mitos sobre la cooperación con un socio externo de desarrollo de software
    • De EE.UU. a Europa: ¿Por qué las startups estadounidenses deciden trasladarse a Europa?
    • Comparación de los polos de desarrollo de Tech Offshore: Tech Offshore Europa (Polonia), ASEAN (Filipinas), Eurasia (Turquía)
    • ¿Cuáles son los principales retos de los CTO y los CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Condiciones de uso del sitio web

    Copyright © 2025 por The Codest. Todos los derechos reservados.

    es_ESSpanish
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean nl_NLDutch etEstonian elGreek es_ESSpanish