Se suas equipes de desenvolvimento trabalham com ReactJS, você deve considerar estas práticas recomendadas.
Se você está pesquisando sobre a melhor forma de estruturar a estrutura de pastas do seu aplicativo React, sem dúvida já se deparou com uma grande variedade de opiniões. Embora este tópico possa ser um pouco subjetivo, existem algumas diretrizes que é melhor seguir. Portanto, quer você seja completamente novo no desenvolvimento do React ou já tenha experiência com uma opinião diferente, há algo aqui para todos.
#1 Práticas recomendadas para estrutura de pastas React
Agrupar pastas por recursos
Se você conhece os recursos que serão incluídos em seu aplicativo ReactJS, poderá criar facilmente uma estrutura de pastas com base nesses recursos principais. Ao fazer isso, é possível manter uma estrutura de diretórios bem organizada para seu aplicativo e você saberá exatamente qual código vai para onde. Isso também torna muito mais fácil depurar e colaborar.
Evite aninhamento profundo
Ao criar sua estrutura de pastas, você não quer acabar com muitas pastas aninhadas. Se você estiver fazendo isso no início, talvez seja necessário repensar sua hierarquia de pastas e dividir as coisas de maneira mais granular. Um dos maiores problemas com o aninhamento profundo é que se torna um desafio escrever importações relativas entre essas pastas profundamente aninhadas ou atualizá-las quando os arquivos são movidos.
Pensar demais é seu inimigo
Ao iniciar o processo de criação da estrutura de pastas do seu projeto, não pense demais. Se você estiver com dificuldades para começar (porque seu cérebro está pensando em círculos), basta despejar todos os arquivos iniciais na raiz do documento. À medida que o projeto continua, você verá exatamente como deve ser a estrutura de pastas. Assim que ficar claro, crie as pastas e mova os arquivos para seus novos lares. Você pode até começar com uma pasta src dentro da pasta base do projeto e depois mover os arquivos para fora dessa pasta conforme as coisas se tornam óbvias. Apenas certifique-se de não deixar seu projeto nesta estrutura de pasta única, pois as coisas podem ficar muito confusas à medida que o projeto cresce.
Você poderia simplesmente começar com uma única pasta base (src) e duas subpastas (App e List) para abrigar os componentes do aplicativo, que podem ser parecidos com isto:
- src/ --- App/ ----- index.js ----- App.js ----- App.test.js ----- App.style.css --- List/ ----- index.js ----- List.js ----- List.test.js ----- List.style.css
Componentes e utilitários separados
Você também pode estruturar suas pastas separando os componentes dos ganchos. Esse tipo de estrutura de pastas pode ser assim:
- src/ --- components/ ----- App/ ------- index.js ------- component.js ------- test.js ------- style.css ----- List/ ------- index.js ------- component.js ------- test.js ------- style.css --- hooks/ ----- useClickOutside/ ------- index.js ------- hook.js ------- test.js ----- useScrollDetect/ ------- index.js ------- hook.js ------- test.js
Nº 2 Práticas recomendadas da biblioteca de testes React
Teste o comportamento, não a implementação
Há uma grande diferença entre comportamento e implementação. A diferença é simples:
- Ao testar o comportamento, você não se importa como chegará à resposta, apenas se a resposta está correta sob um determinado conjunto de circunstâncias.
- Ao testar a implementação, você não se importa com a resposta, apenas faz algo específico enquanto descobre.
É mais provável que o teste de comportamento chegue a uma conclusão viável e repetível, portanto, testar dessa maneira é sua melhor opção.
Use métodos de renderização personalizados para modelos de dependência
Ao usar um método de renderização personalizado para simular dependências, você pode evitar ter que passar pela mesma configuração sempre que executar um teste. À medida que seu projeto for ampliado, você certamente não desejará passar pela mesma configuração em todos os testes. Com métodos de renderização personalizados, seus testes de simulação também são mais repetíveis e fáceis de manter.
Funcionalidade de teste, não implementação
Se você se concentrar em testar detalhes de implementação, o que estará fazendo é testar como seu código é escrito, não o que ele faz. Ao seguir esse caminho, se você alterar seu código, seus testes falharão, mesmo que a funcionalidade do código não tenha mudado. Se, em vez disso, você testar a funcionalidade, esses testes permanecerão viáveis, mesmo se você alterar a implementação do seu código.
Escreva testes que não sejam interrompidos quando a interface do usuário for alterada
Sua IU vai mudar. Isso é inevitável. Ao criar seus testes, você deve ter isso em mente e escrevê-los de forma que eles não sejam interrompidos caso a IU mude. Certifique-se de criar testes que foquem no comportamento de um componente e não na implementação. Por exemplo, em vez de testar se um menu usa a classe CSS correta, você deve testar para ter certeza de que clicar no menu fornece os resultados esperados.
Não teste aquilo que o React já testa
A biblioteca React já está muito bem testada. Ao usar componentes da biblioteca, você não precisará testá-los. Em vez disso, concentre seus testes nos componentes e no código que você escreve. Evite tais redundâncias, pois elas apenas desperdiçam tempo.
Use auxiliares de simulação de eventos
O React inclui vários auxiliares de simulação — como change , click e keydown — que simulam eventos sem realmente acioná-los. Certifique-se de usar esses auxiliares, em vez do fireEvent, pois isso realmente despacha um evento para o DOM. Dado que o nó DOM não consegue lidar com certos tipos de eventos, isso pode causar problemas.
Sempre use Act para testar eventos assíncronos
Na mesma linha, você deve sempre usar act para testar eventos assíncronos. Com eventos assíncronos, a React Testing Library aguardará a conclusão das tarefas antes de executar qualquer asserção. O problema é que só funciona se as tarefas assíncronas forem iniciadas com um manipulador de eventos. Para evitar esse problema, envolva sua tarefa assíncrona em uma chamada act para que a React Testing Library permaneça até que todas as tarefas assíncronas sejam concluídas antes de executar as asserções.
Afirme apenas uma coisa por teste
Isto é crítico. Se você afirmar várias coisas por teste e uma delas falhar, o teste falhará e você não saberá qual afirmação está causando o problema. Em vez disso, concentre seus testes em uma única afirmação para que, caso o teste falhe, você saiba exatamente qual afirmação é problemática.
Mantenha seus testes simples e focados
Outro aspecto importante dos testes é mantê-los simples. Quando você cria testes excessivamente complexos, fica mais desafiador depurar os problemas. Isto é especialmente verdadeiro à medida que seu projeto se torna mais complexo.
Nº 3: Práticas recomendadas de segurança de reação
Use proteção padrão de script entre sites com vinculação de dados
Embora o React seja bastante seguro, ele ainda pode ser vulnerável a coisas como cross-site scripting (XSS). Por exemplo, você deve sempre usar chaves para vinculação de dados padrão. Isso garante que o React escapará automaticamente dos valores para proteção contra ataques XSS. Aqui está um exemplo.
Em vez de:
<form action={data}>
Usa isto:
<div>{data}</div>
Evite injeção de script baseada em URL
Usando o protocolo javascript:, os URLs podem conter conteúdo dinâmico que pode levar à injeção de script baseado em URL. Para evitar isso, use uma função de análise de URL nativa e, em seguida, combine a propriedade do protocolo analisada com uma lista de permissões.
Use uma biblioteca de saneamento
Com ReactJS, o HTML pode ser inserido diretamente em nós DOM renderizados com perigosamenteSetInnerHTML, o que possibilita aos desenvolvedores inserir diretamente conteúdo HTML dentro de um elemento HTML em um aplicativo React. Ao inserir conteúdo dessa maneira, ele deve sempre ser higienizado usando uma biblioteca de higienização, como DOMPurify. Use isso em quaisquer valores antes de serem colocados na propriedade perigosamenteSetInnerHTML. Um exemplo disso, é assim:
import purify from "dompurify"; <div dangerouslySetInnerHTML={{ __html:purify.sanitize(data) }} />
Verifique se há vulnerabilidades de dependência conhecidas
Se você estiver usando componentes de terceiros, verifique cuidadosamente se há vulnerabilidades que eles possam conter. Como esses componentes são pré-construídos por outro programador (ou equipe), você não quer apenas confiar que esses componentes foram testados quanto a problemas. Se não tiver certeza da segurança de um componente, teste-o antes de implementá-lo.
Evite ataques de injeção JSON
Os dados JSON são comumente enviados com páginas renderizadas no lado do servidor no React. Ao fazer isso, sempre escape < caracteres com qualquer valor benigno. Ao fazer isso, você evita ataques de injeção.
Aqui está um exemplo para ilustrar essa prática:
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace( /</g, ’\\u003c’)}
Use versões seguras do React
Sempre certifique-se de estar usando a versão mais recente do React. Caso contrário, você corre o risco de usar uma versão que contém vulnerabilidades, algumas das quais podem ser críticas. Isso vale tanto para reagir quanto para reagir.
Use um linter
Existem ferramentas, chamadas linters, que podem ajudar a detectar quaisquer problemas de segurança na sua base de código. Um desses linters é Ferramenta de configuração ESLint React Security, que é de código aberto e está disponível gratuitamente. Os linters não devem ser usados apenas no seu código personalizado, mas também no código da biblioteca. É sempre melhor prevenir do que remediar.
Nº 4 Práticas recomendadas de autenticação React
Use uma biblioteca
Quando você precisa depender de autenticação para seu aplicativo, é sempre melhor contar com uma biblioteca. Lembre-se de que a autenticação é um negócio sério e pode levar a muitos riscos. Em vez de escrever código personalizado, que pode estar repleto de problemas de segurança, recorra a uma biblioteca pré-construída para o recurso. Você encontrará muitas bibliotecas de autenticação React disponíveis que podem servir a muitas funções diferentes. Encontre um que atenda às suas necessidades e use-o.
Não armazene dados confidenciais em armazenamento local
Em algum momento você terá que armazenar dados confidenciais, alguns dos quais podem ser dados de usuário/cliente. Quando você armazena dados em armazenamento local (do lado do cliente), significa que qualquer pessoa que tenha acesso ao dispositivo (ou mesmo aplicativos de terceiros) pode acessar esses dados, o que pode levar a problemas de segurança. Em vez de armazenar esses dados no armazenamento local, use uma opção mais segura, como o armazenamento de sessão. Melhor ainda, não armazene informações confidenciais no dispositivo local… ponto final.
Proteja seus endpoints de API
Um ponto de segurança que alguns ignoram são os endpoints da API. O problema dos endpoints é que se um invasor conseguir obter acesso a um (ou mais), ele terá acesso a tudo, inclusive aos dados do cliente. Um método de proteção de endpoints de API é com JSON Web Tokens (JWTs), que é um método padrão do setor para transmissão segura de informações. Antes que as informações sejam transmitidas, o token deve ser verificado no seu servidor.
Se JWTs não forem uma opção, você deveria pelo menos usar HTTPS para criptografia de dados. Dessa forma, se um invasor obtiver acesso a uma API, pelo menos os dados serão criptografados e não poderão ser lidos facilmente. O uso de HTTPS também tem o benefício adicional de proteção contra ataques man-in-the-middle, que é mais uma maneira de um invasor obter acesso aos seus dados.
Criptografe senhas e outras informações confidenciais
Falando em criptografia, nunca deixe senhas e outras informações confidenciais descriptografadas. Fazer isso deixa seu aplicativo ou serviço aberto a ataques. Pior ainda, se o seu aplicativo ou serviço for usado por consumidores ou clientes e eles armazenarem senhas e outras informações no aplicativo, se essas informações não estiverem criptografadas, esses dados poderão ser acessados e lidos por hackers. Deixar os dados do cliente/consumidor abertos dessa forma nunca deveria ser feito.
Implementar limitação de taxa em tentativas de login
Se não estiver usando a limitação de taxa para tentativas de login, você deixará seu aplicativo ou serviço aberto para ataques de força bruta. Com isso em jogo, é apenas uma questão de tempo até que um hacker consiga invadir seu aplicativo/serviço e roubar os dados contidos nele. Você deve limitar as tentativas de login a, digamos, cinco tentativas fracassadas em um determinado período de tempo. Caso esse limite seja excedido, a conta deverá ser bloqueada por um determinado período de tempo. Ao fazer isso, seu sistema terá a chance de detectar e relatar essas tentativas fracassadas. Sem limitação de taxa, os invasores podem continuar invadindo os logins até acertarem e obterem acesso ao seu aplicativo ou serviço.
Use 2FA ou MFA para segurança extra
Muitos usuários hesitam em usar a autenticação de dois fatores (2FA) ou a autenticação multifator (MFA) para logins. Depois de finalmente entenderem por que isso é usado (e que não é o inconveniente que supunham), os usuários aceitam essas camadas adicionais de segurança. Em vez de tornar o 2FA ou o MFA opcional, considere torná-lo obrigatório. Embora 2FA e MFA não sejam perfeitos, eles certamente tornam mais desafiador para possíveis invasores obterem acesso ao seu aplicativo ou serviço. Qualquer segurança extra que você possa adicionar ao seu aplicativo, serviço ou site deve ser considerada obrigatória.
Não use e-mail como nome de usuário
Falando em segurança de conta, considere proibir endereços de e-mail como nomes de usuário. Por que? Endereços de e-mail para nomes de usuário são uma prática muito comum, o que significa que os hackers têm menos problemas para adivinhar um critério de login. Em vez de usar endereços de e-mail para nomes de usuário, considere forçar os usuários a criar nomes de usuário exclusivos, o que torna consideravelmente mais desafiador para um hacker quebrar a autenticação, tornando seu aplicativo consideravelmente mais seguro.
Use autenticação sem senha
Um dos métodos mais seguros de autenticação é sem senha. Em vez de usar uma senha típica para login, os usuários recebem um código único que é enviado para seu número de telefone e, em seguida, usam o código para login. Ainda mais seguro é usar um código de um aplicativo autenticador, como Authy ou Google Authenticator. Como esses códigos são de uso único, não há como um hacker adivinhar a senha – pois não há senha para adivinhar. A única desvantagem da autenticação sem senha é quando os códigos são enviados, via SMS, para um telefone. Esses códigos podem ser interceptados por hackers, o que tornaria consideravelmente mais fácil invadir uma conta. Claro, se o usuário estiver trabalhando com um nome de usuário exclusivo (e não com um endereço de e-mail), mesmo que o hacker intercepte o código, ele terá que saber o nome de usuário associado à conta para obter acesso.
Desconectar usuários inativos
Uma coisa sobre aplicativos móveis e da web é que os usuários trabalharão com eles por um tempo e ficarão entediados com o aplicativo ou não encontrarão mais necessidade de usá-lo. No caso de um aplicativo móvel, esses aplicativos esquecidos tendem a permanecer instalados e as contas conectadas. Isso pode ser um problema de segurança. Para contornar isso, considere incorporar em seu aplicativo/serviço um logout automático após um determinado período de tempo. Quando você desconecta automaticamente esses usuários do aplicativo, terceiros não conseguem desbloquear o telefone e abrir o aplicativo sem precisar primeiro se autenticar. Sim, pode ser um pequeno inconveniente para os usuários que não abrem o aplicativo regularmente, mas tal conveniência não é nada comparada a uma conta hackeada. Se a conta de um usuário for hackeada, não há como saber se o malfeitor infrator não conseguirá obter acesso a outras contas, a um endpoint de API ou ao seu servidor de hospedagem.
Melhores práticas do ReactJS: conclusão
ReactJS é amplamente utilizado em todo o mundo para construir interfaces interativas para aplicativos web e móveis. Dada a difusão desses tipos de aplicativos, cabe aos desenvolvedores seguir sempre as melhores práticas para evitar que hackers obtenham acesso a dados confidenciais, o que pode causar mais problemas do que você pode imaginar.
Com um pouco de cautela desde o início, você pode evitar tal catástrofe. O resultado final é que seus clientes confiarão em seu aplicativo e em sua empresa. Esse nível de confiança não pode ser comprado ou vendido, por isso deve ser considerado um bem inestimável.
Se você gostou deste artigo sobre React, confira estes tópicos;
- Bibliotecas de componentes React UI
- Os 6 melhores IDEs e editores React
- Por que o React é tão popular?
- O que você precisa saber sobre reagir
- Renderização do lado do servidor em React
- Reagir WebSockets: Tutorial