Renderização Condicional
Trabalhar com renderização condicional no React é bastante simples.
Normalmente que trabalha com frameworks e biblitoecas Front-End pode imaginar a utilização de if/else
para fazer a renderização de algum elementom as existem formas mais simples.
Ao invés de:
if (isLoggedIn) {
return <UserGreeting />;
} else {
return <GuestGreeting />;
}
Você pode utilizar o operador ternário:
return isLoggedIn ? <UserGreeting /> : <GuestGreeting />;
Dessa forma o código fica muito mais limpo e fácil de ler.
Também é possível utilizar o operador &&
para fazer a renderização condicional:
isLoggedIn && <UserGreeting />;
Algo bem comum no dia-a-dia é utilização de ternários e verificação se uma condição é verdadeira e caso seja renderizar um elemento.
Imagem uma listagem de usuários e você quer renderizar um botão de excluir apenas para usuários que possuem o nível de acesso admin
.
const users = [
{ name: "John", role: "admin" },
{ name: "Jane", role: "user" },
{ name: "Mary", role: "user" },
];
const UserList = () => {
return (
<ul>
{users.map((user) => (
<li key={user.name}>
{user.name} {user.role === "admin" && <button>Excluir</button>}
</li>
))}
</ul>
);
};
Elemento Variável
Você pode utilizar variáveis para armazenar elementos. Isso pode ser útil para renderizar um elemento ou outro dependendo de uma condição.
const UserGreeting = () => <h1>Bem-vindo de volta!</h1>;
const GuestGreeting = () => <h1>Por favor, faça login.</h1>;
const Greeting = ({ isLoggedIn }) => {
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
};
const App = () => {
const isLoggedIn = true; //image que exista aqui um retorno de um serviço que verifica as credenciais do usuário e o token de acesso
return <Greeting isLoggedIn={isLoggedIn} />;
};
Boas práticas
Utilização de operadores ternários
Algo muito comum é a utilização de operadores ternários para fazer a renderização condicional do código, porém devemos tomar cuidado pra não deixá-lo muito complexo, dificultando a leitra, manutenção, evolução e testes.
Sem contar que a chance de causar um 🐛 aumenta consideravelmente.
// Algo para EVITAR a ser feito
// algumas importações que foram utilizadas abaixo
function Page({ type = "advanced" }) {
return (
<div>
{type === "advanced" ? (
<div>
<h1>Level Advanced</h1>
<p>Texto</p>
<img src="imagem.png" alt="Imagem" />
<div>
<Wallet level={level} />
<Dashboard />
<Button action={handle} />
</div>
</div>
) : type === "basic" ? (
<div>
<h1>Level Basic</h1>
<p>Texto 1</p>
<p>Texto 2</p>
<img src="imagem.png" alt="Imagem" />
<div>
<Wallet level={level} />
<Button action={handle} />
</div>
</div>
) : (
<div>
<p>Texto</p>
<div>
<CreateAccount />
<Button action={handle} />
</div>
</div>
)}
</div>
);
}
O código acima funciona? Sim, perfeitamente.
Mas com a evolução, adição de novos componentes, lógicas e etc, essa abordagem pode ficar bastante confusa, dificultando inclusive o entendimento.
O código acima apresenta alguns problemas:
- Repetição de código, que leva a um aumento desnecessário da complexidade;
- Dificuldade de compreensão, tornando o código menos acessível para outros desenvolvedores;
- Desafios para aplicação de testes unitários, pois é necessário testar todas as condições da página;
- Falta de componentização, o que poderia simplificar a estrutura do código;
- Complexidade devido ao uso excessivo de condicionais (ternário, if/else, switch-case, etc.);
- O código se torna uma "tripa", ou seja, muito extenso e enrolado 🏄.
Isso é algo bastante comum no cotidiano de desenvolvimento. Com facilidade, mais código é adicionado, complicando o entendimento da página.
Uma forma de melhorar o código é a criação de componentes específicos para cada type
e criar um mapa de componentes para realizar a renderização baseado em uma propriedade.
// Algo MELHOR a ser feito
import { AdvancedAccount } from "./AdvancedAccount";
import { BasicAccount } from "./BasicAccount";
import { CreateAccount } from "./CreateAccount";
function getPageComponent(type) {
// mapa de componentes
const components = {
advanced: AdvancedAccount,
basic: BasicAccount,
default: CreateAccount,
};
// caso o tipo não exista no mapa, retorna o componente padrão
return components[type] || components["default"];
}
function Page({ type = "advanced" }) {
const Component = getPageComponent(type);
return (
<div>
<Component />
</div>
);
}
Por que essa abordagem é melhor? Consome mais memória? É mais lenta?
Não, a abordagem é melhor porque deixa o código mais limpo, fácil de ler e entender, além de facilitar a manutenção e evolução do código.
Com a evolução da lógica, podemos simplesmente adicionar novos componentes ao mapa, mantendo o mesmo formato. Isso facilita a adição de testes unitários, pois podemos testar a função getPageComponent isoladamente, passando simplesmente o atributo type, sem ter que renderizar a página várias vezes para cobrir cada caso de uso.
As duas abordagens funcionam? Como já mencionado, sim. Mas é sempre bom pensar em boas práticas para manter o código organizado e fácil de evoluir. É muito importante lembrar que não seremos os únicos a trabalhar em um sistema e, mesmo que fôssemos, com certeza amanhã não vamos lembrar o que estávamos pensando naquele dia do desenvolvimento, tornando necessário revisar todo o código.
É essencial ressaltar que esta prática não é recomendada para todas as situações. Frequentemente, um excesso de condicionais indica problemas na arquitetura do código.
Buscar sempre a simplicidade e a clareza no código é o ideal. O uso de operadores ternários é aceitável, mas é prudente limitá-lo a casos mais específicos e evitar exageros.
Quer mais boas práticas? Clique aqui.