Erros comuns de iniciantes em ReactJS
Miguel Barbosa
Posted on October 18, 2023
Ao longo de nosso tempo de estudo, percebemos que o React possui uma série de detalhes que nos pegam desprevenidos e ocasionam comportamentos inesperados ou erros não tão detalhados que acabam nos confundindo.
Dedico este artigo aos iniciantes em React que, assim como o meu eu do passado, perdeu um tempinho tentando resolver tais problemas. 😅
Sumário
- A propriedade style no JSX
- Acessar um valor que ainda não existe
- Esquecer a propriedade key quando exibindo uma lista
- Verificando se uma lista está vazia
A propriedade style no JSX
JSX foi construído para ser bem similar ao clássico HTML. Mas há algumas diferenças que, mesmo bem documentadas, acabamos esquecendo. Dentre essas, há o uso de className
no lugar de class
e a forma com que atribuímos o valor da propriedade style
.
No HTML atribuímos os valores em uma string e escrevemos parecido com o CSS padrão:
<button style="height: 3rem; background-color: blue;">
A really cool button
</button>
Já dentro do JSX, precisamos atribuir em formato de objeto javascript e usando camelCase para propriedades que contém nomes compostos.
Mas há uma pegadinha! 🧐
Em outras propriedades do JSX, geralmente atribuímos o valor entre um par de chaves:
return (
<input placeholder={"My beautiful input"} />
)
Porém, quando se trata da propriedade style
precisamos inserir mais um par de chaves para que consigamos atribuir os valores de nossos estilos:
return (
<button style={{ height: "3rem", backgroundColor: "blue" }}>
A really cool button
</button>
)
Isso acontece porque o primeiro par de chaves serve para criar um expression slot, onde podemos atribuir qualquer expressão javascript como por exemplo um condicional ternário. O segundo par de chaves é um objeto javascript contendo os nossos estilos.
Acessar um valor que ainda não existe
Digamos que você possui um estado que guardará dados que serão providos por uma api, então tentará exibir valores da seguinte forma:
import React from 'react';
export const PokemonsList = () => {
const [pokemons, setPokemons] = React.useState();
React.useEffect(() => {
fetch("https://pokeapi.co/api/v2/pokemon")
.then((response) => response.json())
.then((data) => setPokemons(data.results));
}, [])
return (
<div>
{pokemons.map((pokemon) => (
<h2>{pokemon.name}</h2>
))}
</div>
);
}
E então, vemos o seguinte erro ao tentar iterar pokemons.map()
:
Cannot read properties of undefined (reading 'map')
A requisição acontece de forma assíncrona, então em primeiro momento, a variável pokemons
irá conter o valor que atribuímos ao iniciar o estado (que nesse caso deixamos vazio), ou seja: undefined
.
Temos duas formas de resolver isso:
- Iniciando o estado como um array vazio:
- const [pokemons, setPokemons] = React.useState();
+ const [pokemons, setPokemons] = React.useState([]);
- Usando o optional chaining:
- {pokemons.map((pokemon) => (
+ {pokemons?.map((pokemon) => (
Inserir ?.
antes de acessar um método ou uma propriedade de um objeto que ainda não existe, faz com que o javascript retorne undefined
em vez de um erro.
Lembre-se de usar o optional chaining sempre que uma propriedade de um objeto pode ser
null
ouundefined
! ☝🤓
Esquecer a propriedade key quando exibindo uma lista
Muitas vezes ao renderizar uma lista de itens usando .map
, acabamos esquecendo um detalhe essencial para o React: a propriedade key
.
Warning: Each child in a list should have a unique "key" prop.
Quando renderizamos uma lista, precisamos dar um pouco mais de contexto para que o React consiga identificar cada item. E o valor da propriedade key
deve ser único.
É comum vemos em alguns lugares o index
da iteração sendo usado:
return (
<div>
{pokemons.map((pokemon, index) => (
//usando index
<h2 key={index}>{pokemon.name}</h2>
))}
</div>
);
⚠️ Mas em alguns casos, isso é uma má ideia. ⚠️
O valor índex não está ligado a cada item específico da lista, mas sim a suas posições.
Em uma situação onde a ordem da lista mudará, o React perde a referência de cada um dos itens resultando em problemas de performance, renderização e até acessibilidade.
Para evitar tais problemas devemos atribuir um valor realmente único de cada item. Em nosso caso, onde estamos usando dados de uma api externa, é esperado que todo item tenha um id
único:
return (
<div>
{pokemons.map((pokemon) => (
//usando id
<h2 key={pokemon.id}>{pokemon.name}</h2>
))}
</div>
);
Mas em casos onde tal valor não existe, podemos criar o nosso próprio id
único da seguinte maneira:
const pokemonsWithoutIds = fetch("/pokemons/without-ids")
.then((response) => response.json())
.then((data) => return data.results);
//criando uma nova lista
const pokemonsWithIds = pokemonsWithoutIds.map(item => {
return {
...item,
//atribuindo um id único para cada item
id: crypto.randomUUID(),
};
});
O método crypto.randomUUID
é totalmente seguro de usar, já que possui suporte em todos navegadores atuais.
Este método retornará um valor parecido com 0bf9b4a4-6bb4-11ee-b962-0242ac120002
, que é um universally unique identifier.
Verificando se uma lista está vazia
Digamos que nosso objetivo é mostrar condicionalmente uma lista somente quando ela não estiver vazia. É comum pensarmos da seguinte forma:
const [pokemons, setPokemons] = React.useState([]);
return (
<div>
{pokemons.length && <PokemonList pokemonsData={pokemons} />}
</div>
);
Em nosso HTML veremos um simples 0. Isso ocorre porque diferente de outros valores falsy (""
, false
, null
), o número 0 é válido dentro do JSX. Afinal, em algumas ocasiões queremos de fato exibi-lo.
Para termos o comportamento esperado podemos fazer uma verificação realmente válida checando se length
é maior que 0: pokemons.length > 0 &&
.
Ou usar um verificador ternário:
return (
<div>
{pokemons.length ? (
<PokemonList pokemonsData={pokemons} />
) : null}
</div>
);
Por hoje é só! 🫡
Acha que faltou algo que não citei?
Ficou com alguma dúvida?
Deixa nos comentários ou me manda uma mensagem no Twitter/X.
Obrigado pela leitura! <3
Posted on October 18, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.