The Codest
  • Sobre nós
  • Serviços
    • Desenvolvimento de software
      • Desenvolvimento de front-end
      • Desenvolvimento backend
    • Staff Augmentation
      • Programadores Frontend
      • Programadores de back-end
      • Engenheiros de dados
      • Engenheiros de nuvem
      • Engenheiros de GQ
      • Outros
    • Aconselhamento
      • Auditoria e consultoria
  • Indústrias
    • Fintech e Banca
    • E-commerce
    • Adtech
    • Tecnologia da saúde
    • Fabrico
    • Logística
    • Automóvel
    • IOT
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • A nossa equipa
  • Case Studies
  • Saber como
    • Blogue
    • Encontros
    • Webinars
    • Recursos
Carreiras Entrar em contacto
  • Sobre nós
  • Serviços
    • Desenvolvimento de software
      • Desenvolvimento de front-end
      • Desenvolvimento backend
    • Staff Augmentation
      • Programadores Frontend
      • Programadores de back-end
      • Engenheiros de dados
      • Engenheiros de nuvem
      • Engenheiros de GQ
      • Outros
    • Aconselhamento
      • Auditoria e consultoria
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • A nossa equipa
  • Case Studies
  • Saber como
    • Blogue
    • Encontros
    • Webinars
    • Recursos
Carreiras Entrar em contacto
Seta para trás VOLTAR
2023-05-19
Desenvolvimento de software

Visibilidade de componentes no React com renderização condicional e proteções

Bartlomiej Kuczynski

Saiba como simplificar e melhorar a visibilidade de componentes no React usando renderização condicional e componentes de proteção.

Hoje gostaria de falar sobre como controlar visibilidade dos componentes no React. Mas antes de começarmos, há uma pequena
isenção de responsabilidade:

A solução apresentada não é muito segura no sentido de proteger a sua aplicação contra "hackers" (sejam eles quem forem).
Lembre-se de que precisa de proteger os seus pontos finais e de utilizar boas práticas na conceção da aplicação. Esta solução apenas
torna o seu trabalho um pouco mais fácil.

Tarefa, solução do problema ou o que gostaríamos de alcançar

Uma das funcionalidades mais comuns é mostrar o componente apenas para um grupo de utilizadores que têm alguns direitos específicos,
funções ou privilégios. A solução comum é adicionar alguns ses para código, verificar manualmente as condições e mostrar ou não os elementos.

Vamos dar uma olhadela a SimpleAppHeader que contém poucos elementos de navegação.

<!-- wp:paragraph -->
<p><code>typescript jsx<br>
export const SimpleAppHeader: FC = () =&gt; {<br>
    return (<br>
        <header><br>
            <nav><br>
                <ul><br>
                    {&lt;<br>
                        currentUser.role === "ADMIN" &amp;&amp;<br>
                        <li>Componente apenas para administradores</li><br>
                    }<br>
                    {<br>
                        currentUser.role === "USER" &amp;&amp;<br>
                        <li>Componente apenas de utilizador</li><br>
                    }<br>
                    {<br>
                        (currentUser.role === "ADMIN" || currentUser.role === "USER") &amp;&amp;<br>
                        <li>Componente somente para administrador e usuário</li><br>
                    }<br>
                    <li>Elemento de uso geral</li><br>
                </ul><br>
            </nav><br>
        </header><br>
    )<br>
}<br>
</code></p>
<!-- /wp:paragraph -->

Não parece "mau". Provavelmente, poderia encapsular as verificações em funções para reduzir a complexidade. utilizador atual é um objeto
que tem papel mas pode ser qualquer coisa que queiramos utilizar como objeto do nosso mecanismo de controlo.

Este código tem alguns problemas. Se projeto cresce, provavelmente usamos essas construções em muitos sítios. Por isso, precisamos de copiar,
de alguma forma, condições. Este código é difícil de manter e de alterar no futuro. Especialmente quando as regras de acesso mudam durante
tempo, por exemplo, precisamos de mudar utilizador atual noutra coisa. É muito difícil de testar. É preciso escrever muitos testes
apenas para verificar se o seu estado está bem.

Simplificação

É altura de simplificar um pouco este código. Podemos extrair alguns métodos e tornar o código mais curto e menos complexo:

const isAdmin = (role: string): booleano => role === "ADMIN";
const isUser = (função: string): booleano => função === "USUÁRIO";
const isAdminOrUser = (role: string): boolean => isAdmin(role) || isUser(role);

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

{

isAdmin(currentUser.role) &&
Componente apenas para administradores

}
{
isUser(currentUser.role) &&

Componente apenas do utilizador

}
{
(isAdminOrUser(currentUser.role)) &&

Componente apenas para administradores e utilizadores

}

Elemento de utilização geral

)
}
```

Parece prometedor. Reduzimos o ruído e a repetição de linhas. O código é mais legível e mais fácil de manter. Mas veja o
função isAdminOrUser. Só temos duas funções. Se introduzirmos uma terceira função, teremos de criar outro conjunto de funções
que combina papéis. Está na altura de outra versão.

Filtragem

Vamos introduzir a função hasRole que será o substituto do nosso isX funções.

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

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

{

hasRole(currentUser.role, ["ADMIN"]) &&
Componente apenas para administradores

}
{
hasRole(currentUser.role, ["USER"]) &&

Componente apenas do utilizador

}
{
hasRole(currentUser.role, ["ADMIN", "USER"]) &&

Componente apenas para administradores e utilizadores

}

Elemento de utilização geral

)
}
```

Agora está com bom aspeto. Continuamos a ter condições na parte html do código, mas agora podemos testar hasRole função e confiar que
será utilizado com o conjunto correto de parâmetros. Adicionar ou alterar funções é agora mais fácil. Utilizamos um array que contém todos os
funções de que necessitamos.

No entanto, esta solução está ligada a utilizador atual objeto. Parte-se do princípio de que o objeto é de alguma forma global ou de fácil acesso em
em qualquer lugar da aplicação. Por isso, podemos tentar encapsular isto. Claro que podemos movê-lo para hasRole função:

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

Mas isso dá nós quase nada.

O Guarda Componente

Está na altura de criar um componente que encapsule toda a lógica. Dei-lhe o nome de Guarda e é assim que o quero utilizar.

 export const GuardedAppHeader: FC = () => {
     return (
         
             
  • Componente apenas para administradores
  • Componente apenas para utilizadores
  • Componente de administrador e utilizador
  • Elemento de uso geral
); }

O componente precisa de duas propriedades. Primeiro crianças responsável pelo conteúdo que é guardado. Segundo funções necessárias que
manipular o conjunto de funções que nos dá acesso.

Precisamos de representar esta estrutura. É muito simples. Estendemos o tipo React.AdereçosComCrianças que tem crianças
propriedade. É claro que pode adicionar manualmente essa propriedade ao seu tipo e omitir a extensão.

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

O componente em si também é simples. Vamos reutilizar hasRole função aqui.

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

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

E eu podia dizer para pararmos aqui, mas seria demasiado fácil. Agora temos componente, e podemos usá-lo ao extremo 😀

`GuardService`

O primeiro passo será a externalização dos controlos. utilizador atual é um valor codificado. Gostaria de encapsular este valor
para algum serviço, que "saberá" como verificar os papéis. Tecnicamente, isso significa que mudamos hasRole para outra função
classe.

Eu crio uma interface simples IGuardService que tem apenas uma propriedade - hasRole.

interface de exportação IGuardService {
checkRole: (roles: string[]) => boolean;
}

Agora, a implementação simples poderia ser assim

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

Para o utilizar, é necessário alterar IGuardProperties e caso de utilização.

exportar interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
guardService: IGuardService;
}

// ...

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

Componente apenas para administradores
 

Componente apenas para utilizadores

Componente de administrador e utilizador
 
 

Elemento de utilização geral

 

);
}
```

Agora o componente tem o seguinte aspeto:

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

Muito melhor. GuardService separam-nos da lógica que verifica os papéis. Podemos alterá-la sem consequências para a nossa
componente. Um caso de utilização comum é a utilização de uma simulação nos testes e uma implementação "real" no código de produção.

Elemento proibido

A próxima melhoria será o tratamento de dados personalizados Proibido elemento. A solução atual apresenta um elemento vazio. Primeiro precisamos de
mudança IGuardProps função de adição que será processada nesse elemento.

 exportar interface IGuardProps extends React.PropsWithChildren {
     requiredRoles: string[];
     guardService: IGuardService;
     forbidden?: () => React.ReactNode;
 }

Esta propriedade é opcional e o seu nome termina com um carácter de ponto de interrogação. Por isso, pode ser uma função ou indefinido. Precisamos de
tratá-lo em Guarda 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 apenas para administradores
 

Componente só para utilizadores

Proibido - apenas o moderador pode ver isto
}>
 

Componente do moderador

 

Componente Admin e Utilizador
 
 

Elemento de utilização geral

 

);
}
```

Flexibilidade de tipos

Chegou a altura da última grande mudança. A versão atual do componente suporta apenas funções como corda. Poderíamos ter vários
tipos de propriedades que gostaríamos de verificar. Números ou tipos personalizados não são nada de especial. Irei adicionar suporte para genéricos.

O primeiro passo é a mudança de IGuardService interface. As implementações dependerão do tipo de valor testado. Pode ser
ser qualquer coisa, por isso a interface deve tratar disso.

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

Agora é necessário um conjunto de PAPEL tipo genérico. A nossa implementação simples vai mudar um pouco.

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

Precisamos de adicionar um parâmetro de tipo, mas podemos preparar uma implementação que suporte IRole interface.

interface IRole {
nome: string;
}

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

O segundo passo é propagar esta alteração para IGuardProps.

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

E, respetivamente, para Guarda 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()}
             
         );
     }
 }

E os nossos casos de utilização

export const AppHeader: FC = () =&gt; {
     const guardService = new SimpleGuard();
     const roleService = new RoleGuardService();
     return (
         <header>
             <nav>
                 <ul>
                     <Guard<IRole&gt; requiredRoles={{[{nome: "ADMIN"}]} guardService={roleService}&gt;
                         <li>Componente apenas para administradores</li>
                     </Guard>
                     <Guard<string&gt; requiredRoles={["USER"]} guardService={guardService}&gt;
                         <li>Componente apenas do utilizador</li>
                     </Guard>
                     <Guard<string&gt; requiredRoles={["MODERATOR"]} guardService={guardService}
                                    forbidden={() =&gt; <div>Proibido - apenas o moderador pode ver isto</div>}>
                         <li>Componente moderador</li>
                     </Guard>
                     <Guard<string&gt; requiredRoles={["USER", "ADMIN"]} guardService={guardService}&gt;
                         <li>Componente Admin e Utilizador</li>
                     </Guard>
                     <li>Elemento de utilização geral</li>
                 </ul>
             </nav>
         </header>
     );
 }

Neste exemplo, utilizo ambas as implementações de IGuardservice apenas para fins ilustrativos. Em casos reais de utilização
provavelmente utilizar apenas um.

Componentes especializados e nesting

O Guarda pode ser aninhado. Lembre-se apenas de que o acesso será resolvido por ordem a partir da instância mais externa.

export const NestAppHeader: FC = () =&gt; {
     const guardService = new SimpleGuard();
     return (
         <header>
             <nav>
                 <ul>
                     <Guard<string&gt; requiredRoles={["USER", "ADMIN"]} guardService={guardService}&gt;
                         <Guard<string&gt; requiredRoles={["ADMIN"]} guardService={guardService}&gt;
                             <li>Componente apenas para administradores</li>
                         </Guard>
                         <Guard<string&gt; requiredRoles={["USER"]} guardService={guardService}&gt;
                             <li>Componente apenas do utilizador</li>
                         </Guard>
                         <li>Componente Admin e Utilizador</li>
                         <Guard<string&gt; requiredRoles={["MODERATOR"]} guardService={guardService}
                                        forbidden={() =&gt; <div>Proibido - apenas o moderador pode ver isto</div>}>
                             <li>Componente moderador</li>
                         </Guard>
                     </Guard>
                     <li>Elemento de utilização geral</li>
                 </ul>
             </nav>
         </header>
     );
 }

No exemplo acima Componente moderador nunca poderia aparecer, porque o utilizador só pode lidar com uma função. Primeiro Guarda limites
papéis para ADMIN e UTILIZADOR, portanto MODERADOR nunca passará no primeiro controlo.

Podemos criar componentes especializados que ocultam algumas propriedades.

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

}

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

Componente apenas para administradores
 


Componente apenas para utilizadores


Proibido - apenas o moderador pode ver isto
}>

Componente moderador



Componente Admin e Utilizador

 

Elemento de utilização geral

);
}
```

Neste caso AdminGuard predefinir ADMIN função. Em consequência, é necessário definir explicitamente o tipo de PAPEL tipo
parâmetro.

Resumir

Neste artigo, mostro-lhe como criar e utilizar Guarda componente no React. Partimos de um código complexo que é difícil de
ler e manter. Desenvolvemo-lo para um estado mais amigável para o programador e introduzimos um componente funcional personalizado. De seguida
estender o componente adicionando funcionalidades extra, refactorizar o serviço de extração e, finalmente, adicionar tipos genéricos.

Finalmente, temos um componente que pode ser aninhado e é fácil de testar e manter.

Artigos relacionados

Desenvolvimento de software

Prós e contras do React

Porque é que vale a pena utilizar o React? Que vantagens tem esta biblioteca JavaScript? Para saber as respostas, mergulhe neste artigo e descubra os benefícios reais da utilização do React.

The Codest
Cezary Goralski Software Engineer

Subscreva a nossa base de conhecimentos e mantenha-se atualizado sobre os conhecimentos do sector das TI.

    Sobre nós

    The Codest - Empresa internacional de desenvolvimento de software com centros tecnológicos na Polónia.

    Reino Unido - Sede

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

    Polónia - Pólos tecnológicos locais

    • Parque de escritórios Fabryczna, Aleja
      Pokoju 18, 31-564 Cracóvia
    • Embaixada do Cérebro, Konstruktorska
      11, 02-673 Varsóvia, Polónia

      The Codest

    • Início
    • Sobre nós
    • Serviços
    • Case Studies
    • Saber como
    • Carreiras
    • Dicionário

      Serviços

    • Aconselhamento
    • Desenvolvimento de software
    • Desenvolvimento backend
    • Desenvolvimento de front-end
    • Staff Augmentation
    • Programadores de back-end
    • Engenheiros de nuvem
    • Engenheiros de dados
    • Outros
    • Engenheiros de GQ

      Recursos

    • Factos e mitos sobre a cooperação com um parceiro externo de desenvolvimento de software
    • Dos EUA para a Europa: Porque é que as empresas americanas decidem mudar-se para a Europa?
    • Comparação dos centros de desenvolvimento da Tech Offshore: Tech Offshore Europa (Polónia), ASEAN (Filipinas), Eurásia (Turquia)
    • Quais são os principais desafios dos CTOs e dos CIOs?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Direitos de autor © 2026 por The Codest. Todos os direitos reservados.

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