Aumentando a legibilidade do código
A maioria das dicas apresentadas neste artigo dependerá do ES6 (ECMAScript 2015) sintaxe
Desestruturando
A desestruturação pode ser útil para retirar itens individuais de um objeto ou array. Tenha cuidado ao usar com arrays, pois você pode se confundir facilmente renomeando alguma propriedade de maneira errada, vamos dar uma olhada em um exemplo:
_14// alunos => [idade, série]_14const alunos = [_14 [19, 80.9],_14 [21, 75.2],_14 [19, 88.7]_14]_14_14alunos.forEach(([idade]) => idade) // 19, 21, 19_14_14// Mesmo renomeando o primeiro valor como nota, obtemos a idade_14alunos.forEach(([série, idade]) => série) // 19, 21, 19_14_14// Podemos pular valores de uma array usando uma vírgula (,)_14alunos.forEach(([, nota]) => nota) // 80.9, 75.2, 88.7
Agora usando um objeto.
_14const alunos = {_14 Kevin: {_14 idade: 19,_14 nota: 80,9,_14 },_14 Laura: {_14 idade: 21,_14 nota: 75,2,_14 },_14};_14_14const { Kevin } = alunos;_14_14Kevin.nota; // 80.9
Usando acessadores de propriedade
Podemos ter acesso a uma propriedade de duas maneiras, você pode usar o simples ponto .
, ou a notação de acesso colchete []
.
_6const Kevin = {_6 idade: 19,_6 nota: 80,9_6}_6_6Kevin['nota']) // 80.9
Um exemplo com CSS Modules
: usando um nome de classe com caracteres especiais.
_3const Texto = () => {_3 return <p className={styles['primary-text']}>Olá!</p>_3}
Se desejar, você também pode acessar as propriedades dinamicamente:
_9const mensagensDeStatus = {_9 ERRO: 'servidor morreu',_9 CARREGANDO: 'Estamos dando o nosso melhor',_9 OCIOSO: 'Aguardando entrada'_9}_9_9const status = getCurrentStatus() // CARREGANDO_9_9mensagensDeStatus[status] // Estamos dando o nosso melhor
Usando parâmetros de função de objeto
Isso é situacional, mas geralmente quando tenho mais de 2 ou 3 parâmetros em uma função, uso esse método. Compare as funções abaixo:
_12const retorneListaRandomica = (tamanhoDaLista, variacaoDeConteudo, delayEmMS) =>_12 nova Promessa((resolve) => {_12 const numeroRandomico = () => Math.ceil(Math.random() * variacaoDeConteudo);_12_12 const arrayGerada = Array(tamanhoDaLista)_12 .fill(0)_12 .map((_) => numeroRandomico());_12_12 setTimeout(() => resolve(generatedArray), delayEmMS);_12 });_12_12retorneListaRandomica(8, 5, 2000).then((array) => array); // [4, 4, 5, 1, 4, 5, 1, 4]
Desculpe, não consegui pensar em nada melhor do que isso. Mas vamos agora dar uma olhada nos parâmetros em objetos.
_4const retorneListaRandomica = ({ tamanhoDaLista, variacaoDeConteudo, delayEmMS }) =>_4new Promise((resolve) => ... );_4_4retorneListaRandomica({ tamanhoDaLista: 8, delayEmMS: 2000, variacaoDeConteudo: 5 });
Agora, não nos perdemos em nossos parâmetros e não precisamos nos preocupar em ordená-los corretamente.
Dicionários
Às vezes, queremos traduzir alguns retornos ou receber uma mensagem por status. Os dicionários podem fazer isso facilmente sem escrever um monte de if statements
.
Eles foram mencionados anteriormente em um bloco de código antes, então vamos retroceder.
_30const ifStatement = (status) => {_30 if (status === 'ERRO') return 'servidor morreu';_30 if (status === 'CARREGANDO') return 'Estamos tentando o nosso melhor';_30 if (status === 'OCIOSO') return 'Aguardando entrada';_30};_30_30ifStatement('ERRO');_30_30const switchCases = (status) => {_30 switch (status) {_30 case 'ERRO':_30 return 'servidor morreu';_30 case 'CARREGANDO':_30 return 'Estamos dando o nosso melhor';_30 case 'OCIOSO':_30 return 'Aguardando entrada';_30 default:_30 throw new Error(`Status: ${status}, não encontrado`);_30 }_30};_30_30switchCases('ERRO');_30_30dicionário const = {_30 ERRO: 'servidor morreu',_30 CARREGANDO: 'Estamos dando o nosso melhor',_30 OCIOSO: 'Aguardando entrada',_30};_30_30dicionário['ERRO'];
- If statements - Legibilidade média e 3 linhas
- Switch cases - Legibilidade média e 7-9 linhas
- Dicionários - Fácil legibilidade e 3 linhas
Arrow functions
As arrow functions têm suas desvantagens quando comparadas com as normais, mas você pode obter um bom resultado usando-as. Veja algumas comparações abaixo.
_16// Versão normal_16function dobrarValorF(valor) {_16 return value * 2_16}_16_16function retorneNomeDePessoasF(pessoas) {_16 return pessoas.map((pessoa) => pessoa.nome)_16}_16_16// Versão Arrow function_16const dobrarValorA = (valor) => valor * 2_16_16const retorneNomeDePessoasA = (pessoas) => pessoas.map((pessoa) => pessoa.nome)_16_16// Desestruturando_16const retorneNomeDePessoasA = (pessoas) => pessoas.map(({ nome }) => nome)
Usando-os, podemos fazer tudo em apenas uma linha e omitir os parênteses em torno dos parâmetros caso haja apenas um. Na linha 27, combinamos a desestruturação com arrow functions
.
Guard clauses - Evitando o else
Quando usamos if statements
, pretendemos cobrir todos os casos de que precisamos, consequentemente inundando nosso código com o else. Vamos pegar este exemplo que usa o return:
_9const verificarIdade = (idade) => {_9 if (idade < 18) {_9 return 'Não pode entrar na festa.'_9 } else if (idade >= 18 && idade < 21) {_9 return 'Pode entrar, mas não pode beber.'_9 } else {_9 return 'Pode entrar e beber.'_9 }_9}
Na função verificarIdade verificamos o input
, e a lógica funciona assim:
- Se a pessoa estiver mais que 18 anos ela não pode entrar na festa.
- Se tiver menos de 21 anos, mas 18 anos ou mais, pode entrar mas não beber.
- Se forem mais velhos, podem entrar e beber.
Temos alguns problemas neste código que podemos corrigir:
- Na linha 4, não precisamos verificar se a pessoa tem mais de 18 anos porque já a retornamos na linha 2.
- Precisamos apenas retornar uma mensagem, então nos podemos colocar a condição e a declaração de retorno em uma única linha, alguns programadores não gostam dessa forma, então use o que achar melhor para você.
- Podemos substituir as palavras-chave else if e else por
if statements
e até mesmo omitir o else na última linha.
Vamos refatorar e conferir.
_6const verificarIdade = (idade) => {_6 if (idade < 18) return 'Não pode entrar na festa.'_6 if (idade < 21) return 'Pode entrar, mas não pode beber.'_6_6 return 'Pode entrar e beber.'_6}
Veja como podemos usar as formas linha 2
ou linha 3-4
para retornar a mensagem, então use o que parecer melhor para você. Pessoalmente, para mensagens longas, uso o segundo método. Em conclusão, avalie se você precisa usar ou não uma keyword
.
Quando não podemos evitar a keyword
else
Normalmente, não podemos evitar o uso de else se precisarmos retornar a mesma coisa para ambas as condições.
_6const verificarCargos = (usuário) => {_6 if (user.isPremium) renderizarStatusPremium()_6 else renderizarAnuncios()_6_6 return renderizarInterfaceDoAplicativo()_6}
Operador Spread
para passar props no React
Este operador é responsável por obter o restante de um objeto, vamos supor que precisamos mapear uma lista de usuários e retornar um componente de cada usuário. Esta é a lista de usuários:
_10const usuarios = [_10 {_10 nome: "Jorge",_10 idade: 72,_10 peso: 80,_10 altura: 182,_10 trabalho: "Caminhoneiro"_10 },_10 ..._10]
E agora o componente e os props.
Sem operador de spread
:
_6const UserCard = ({ nome, idade, trabalho }) => <></>_6_6const app = () =>_6 users.map(({ nome, idade, trabalho }) => (_6 <UserCard nome={nome} idade={idade} trabalho={emprego} />_6 ))
Usando o operador spread
:
_1const App = () => users.map((user) => <UserCard {...user} />)
Veja como sem precisar de todos os props, ainda podemos passar o operador spread
para o componente. Mesmo desestruturando as props no primeiro exemplo, nosso segundo bloco de código dá muito mais legibilidade.
Short Circuit Evaluation
Às vezes, precisamos apenas de uma condicional curta para definir um valor de variável ou verificar uma condicional e, com o if statements
gastamos muito espaço para coisas simples. Veja estes dois exemplos:
_6// declaração if_6if (estaEnsolarado) roupaEscolhida = RoupaDeVerao_6else roupaEscolhida = RoupaDeInverno_6_6// Short Circuits_6const roupaEscolhida = estaEnsolarado ? RoupaDeVerao : RoupaDeInverno
_5..._5_5if (estaEnsolarado && estouFeliz) return irParaPraia()_5_5...
Para obter mais informações sobre os Short Circuits
, verifique os recursos adicionais no final do artigo.
Evite Short Circuits no React
Sim, eu sei que recomendei o uso de Short Circuits neste artigo, mas às vezes evitá-los pode nos dar uma melhor legibilidade em nosso código. Vejamos alguns exemplos
Short Circuits
_17const componente = ({ isAdmin }) => {_17 const [state, setState] = useState(false)_17_17 return isAdmin ? (_17 <AdminInterface>_17 <>_17 <></>_17 </>_17 </AdminInterface>_17 ) : (_17 <UserInterface>_17 <>_17 <></>_17 </>_17 </UserInterface>_17 )_17}
Declarações if
_20const componente = ({ isAdmin }) => {_20 const [state, setState] = useState(false)_20_20 if (éAdmin)_20 return (_20 <AdminInterface>_20 <>_20 <></>_20 </>_20 </AdminInterface>_20 )_20_20 return (_20 <UserInterface>_20 <>_20 <></>_20 </>_20 </UserInterface>_20 )_20}
Componentes individuais
_7const componente = ({ isAdmin }) => {_7 const [state, setState] = useState(false)_7_7 if (isAdmin) return <AdminInterface />_7_7 return <UserInterface />_7}
Componentes individuais e sem lógica interna
_2const componente = ({ isAdmin }) =>_2 isAdmin ? <AdminInterface /> : <UserInterface />
Exportando tudo do arquivo index
Esse é um truque legal de importação/exportação, que não tem nada a ver com nosso código real, mas podemos obter resultados interessantes usando-o. É assim que costumamos import arquivos:
_3import Cérebro from './Brain.png'_3import pasta from './BriefCase.png'_3import BuildingConstruction from './BuildingConstruction.png'
Agora usando um arquivo index dentro da pasta de imagens:
Veja como transformamos 3 linhas em 1. Observe que não precisamos usar public/Emojis/index
, JavaScript importa automaticamente o arquivo se o nome dele for index
.
Transformando condicionais complicadas em variáveis
Veja um exemplo em que estamos verificando vários condicionais para verificar se podemos renderizar o painel de gerenciamento:
_2if (user.roles.includes('ADMIN') || (user.age > 18 && user.reputation > 10))_2 return renderManagementPannel()
Vamos refatorar o código transformando os complicados condicionais em variáveis:
_4const isAdmin = user.roles.includes('ADMIN')_4const responsibleUser = user.age > 18 && user.reputation > 10_4_4if (isAdmin || responsibleUser) return renderManagementPannel()
Veja como aumentamos as linhas em nosso código, mas nossa equipe trabalhando no aplicativo pode saber facilmente porque a função renderManagementPannel está sendo acionada.