Projetos React podem facilmente se tornar uma bagunça. Perder o controle de onde os arquivos estão localizados é extremamente comum, o que pode levar a ineficiências significativas durante o desenvolvimento. Então, como você pode melhorar e organizar seus projetos React? Organizando todos os arquivos do seu projeto em uma arquitetura de várias camadas.
Como resultado, você sempre saberá como colocar-e encontrar-cada arquivo. Esta é uma virada de jogo. Isso não apenas o tornará um desenvolvedor mais eficiente, mas também tornará seu projeto muito mais sustentável.
Além disso, ao transformar projetos em arquiteturas organizadas, toda a sua equipe também pode se beneficiar. Isso ocorre porque pessoas diferentes podem trabalhar em camadas diferentes, evitando sobreposição e sobrecarga potencial.
Vejamos por que você deseja usar estruturas de várias camadas no React.
Como as estruturas em várias camadas otimizam os aplicativos React
Reutilizando código
Imagine todos os seus projetos React compartilhando a mesma estrutura de arquivo em várias camadas, permitindo que você maximize seu tempo. Em vez de adaptar componentes ou arquivos importados de outras bases de código para seu projeto de destino, esta estrutura de arquivo compartilhada permite que você importe qualquer tipo de arquivo ou fragmento de código de um projeto para outro como uma operação simples de copiar e colar. Isso incentiva a reutilização de código, tornando mais fácil e menos demorado para você construir seu aplicativo.
Por exemplo, digamos que você tenha vários problemas matemáticos em um de seus projetos. Ao usar essa estrutura de arquivo, você não fica tentado a espalhar todas as funções de utilitário necessárias em toda a base de código.
Em vez disso, ele o incentiva a definir um arquivo math-utils.js
onde você pode armazenar todos os seus utilitários matemáticos. Além disso, ao externalizar elementos com a mesma finalidade no mesmo arquivo, você os torna mais reutilizáveis. Na verdade, se você enfrentar problemas semelhantes em um projeto futuro, pode simplesmente copiar o arquivo math-utils.js
definido anteriormente e colá-lo na camada utils
.
Evitando duplicação de código
A consequência de impor uma estrutura em várias camadas é que cada arquivo, função ou parte do código pertence a um determinado lugar. Isso significa que antes de escrever algo novo, você deve olhar primeiro na pasta assumida, o que desencoraja a duplicação de código e a redução do tamanho da compilação.
Um pacote com muito mais código do que o necessário obviamente será maior do que o necessário. Isso não é bom para navegadores, que precisam fazer o download e renderizar o código.
Portanto, evitar a duplicação de código torna seu aplicativo mais limpo, mais fácil de construir e mais rápido quando é renderizado. Por exemplo, sempre que você precisar recuperar os dados retornados de uma API específica, pode ser tentado a seguir esta abordagem:
função FooComponent1 (props) { //... //recuperando dados fetch (`/api/v1/foo`) .então ((resp)=> resp.json ()) .então (função (dados) { resultados const=dados.resultados; //manipulando dados... }) .catch (função (erro) { console.log (erro); }); //lógica do componente... } exportar FooComponent1 padrão
função FooComponent2 (props) { //... //recuperando dados fetch (`/api/v1/foo`) .então ((resp)=> resp.json ()) .então (função (dados) { resultados const=dados.resultados; //tratando dados de uma maneira diferente de FooComponent1... }) .catch (função (erro) { console.log (erro); }); //lógica de componente diferente de FooComponent1... } exportar FooComponent2 padrão
Como você pode ver, FooComponent1
e FooComponent2
são afetados por um problema de duplicação de código. Em particular, o endpoint da API está sendo duplicado, forçando você a atualizá-lo sempre que ele mudar.
Este não é um bom hábito. Em vez disso, você deve mapear a API na camada de API da seguinte maneira:
export const FooAPI={ //... //mapeando a API de interesse get: function () { return axiosInstance.request ({ método:"GET", url: `/api/v1/foo` }); }, //... }
E, em seguida, use-o onde for necessário para evitar a duplicação de código:
import React from"react"; importar {FooAPI} de"../../api/foo"; //... function FooComponent1 (props) { //... //recuperando dados FooAPI .obter() .então (função (resposta) { resultados const=response.data.results; //manipulando dados... }) .catch (função (erro) { console.log (erro); }); //lógica do componente... } exportar FooComponent1 padrão
import React from"react"; importar {FooAPI} de"../../api/foo"; //... function FooComponent2 (props) { //... //recuperando dados FooAPI .obter() .então (função (resposta) { resultados const=response.data.results; //manipulando dados de uma maneira diferente de FooComponent1... }) .catch (função (erro) { console.log (erro); }); //lógica de componente diferente de FooComponent1... } exportar FooComponent2 padrão
Agora, o endpoint da API é salvo em apenas um lugar, como deveria ser sempre.
Aproveitando a sinergia da equipe
Trabalhar com uma estrutura de arquivo bem conhecida significa que os membros das equipes de desenvolvimento estão todos na mesma página e a usam da mesma maneira.
Sempre que um membro da equipe mapeia uma nova API ou cria um novo arquivo utils ou um novo componente, por exemplo, qualquer membro da equipe poderá usá-lo imediatamente. E, como cada arquivo é colocado logicamente em uma pasta específica que todos sabem como (e onde) acessar, a sobrecarga de comunicação é reduzida ou completamente eliminada, agilizando os processos de desenvolvimento da empresa.
Um potencial efeito colateral da construção de estruturas em várias camadas
Criar módulos npm pode ser complexo
Há uma desvantagem potencial em ter uma arquitetura de arquivo tão organizada: os arquivos estão espalhados por muitas pastas, o que o força a usar importações relativas intensivamente. Isso representa um problema conhecido na criação de módulos npm.
As importações relativas estão sujeitas a falhas, especialmente ao tentar encapsular parte de sua base de código para torná-la publicável como módulos autônomos. Por um lado, isso certamente pode representar um desafio adicional ao tentar criar um pacote npm.
Por outro lado, isso pode ser facilmente evitado transformando as importações relativas em importações absolutas não quebráveis, conforme descrito aqui . Essa técnica permite que você gire isso:
importar UserComponent de"../../components/UserComponent"; import userDefaultImage de"../../../assets/images/user-default-image.png"; importar {UserAPI} de"../../apis/user";
Para isso:
importUserComponentfrom"@ components/UserComponent"; importe userDefaultImage de"@ assets/images/user-default-image.png"; importar {UserAPI} de"@ apis/user";
Portanto, usar muitas importações relativas não deve ser visto como um problema real.
Agora, vamos ver como projetar uma arquitetura eficiente em várias camadas para seus projetos em React e JavaScript.
Criando arquitetura multicamadas
Primeiro, vamos dar uma olhada no resultado final da arquitetura multicamadas. Lembre-se de que cada camada de nossa arquitetura deve ser incluída em uma pasta específica . Como esperado, é altamente recomendável dar a essas pastas os mesmos nomes das camadas em que a arquitetura consiste. Dessa forma, a recuperação de um arquivo torna-se intuitiva e rápida. Você também sempre saberá onde colocar um novo arquivo, o que é uma grande vantagem.
Esta é a aparência da estrutura final:
Agora, vamos mergulhar em cada uma das camadas em que consiste a arquitetura apresentada.
1. Camada API
Aproveitando uma promessa-cliente HTTP baseado em , como Axios , você pode definir uma função para cada API da qual seu aplicativo depende, encapsulando toda a lógica necessária para chamá-la. Dessa forma, você pode dividir onde as solicitações de API são definidas de onde são realmente usadas. Vamos ver como essa camada pode ser construída com um exemplo simples:
const axiosInstance=axios.create ({ URL base:'https://yourdomain.org' }); export const UserAPI={ getAll: function () { return axiosInstance.request ({ método:"GET", url: `/api/v1/users` }); }, getById: function (userId) { return axiosInstance.request ({ método:"GET", url: `/api/v1/users/$ {userId}` }); }, criar: função (usuário) { return axiosInstance.request ({ método:"POST", url: `/api/v1/users`, dados: usuário }); }, update: function (userId, user) { return axiosInstance.request ({ método:"PUT", url: `/api/v1/users/$ {userId}`, dados: usuário, }); }, }
Agora, você pode importar o objeto UserAPI
para fazer a chamada onde você precisa, assim:
import React, {useEffect, useState} de"react"; importar {UserAPI} de"../../api/user"; //... function UserComponent (props) { const {userId}=adereços; //... const [user, setUser]=useState (indefinido) //... useEffect (()=> { UserAPI.getById (userId).then ( função (resposta) { //tratamento de resposta setUser (response.data.user) } ).catch (função (erro) { //Manipulação de erros }); }, []); //... } exportar UserComponent padrão;
Ao empregar Promise
tecnologia, você pode coletar todas as suas definições de solicitações de API no mesmo lugar. Mas não vamos perder de vista o objetivo. Este artigo não pretende mostrar o que você pode conseguir com a camada de API, e você pode seguir this e isto para leitura adicional.
Em vez disso, vamos nos concentrar no fato de que, com essa abordagem, você será capaz de definir uma camada totalmente dedicada às solicitações de API. Isso terá toda a lógica para lidar com as solicitações de API salvas em apenas um lugar, em vez de duplicar toda a lógica para chamar uma API sempre que precisar.
2. Camada de ativos
Seu projeto React pode depender de arquivos que não fazem parte estritamente de sua base de código, como arquivos multimídia. Ter um local para armazenar todos eles é a prática recomendada, pois você deve separá-los claramente de seu código. Observe que essa camada pode ser organizada em subpastas com base em tipos ou extensões para mantê-la organizada: