DEV Community

Cover image for Erros comuns de iniciantes em ReactJS
Miguel Barbosa
Miguel Barbosa

Posted on • Updated on

Erros comuns de iniciantes em ReactJS

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

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>
Enter fullscreen mode Exit fullscreen mode

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"} />
)
Enter fullscreen mode Exit fullscreen mode

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>
)
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

E então, vemos o seguinte erro ao tentar iterar pokemons.map():

  Cannot read properties of undefined (reading 'map')
Enter fullscreen mode Exit fullscreen mode

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([]);
Enter fullscreen mode Exit fullscreen mode
  • Usando o optional chaining:
- {pokemons.map((pokemon) => ( 
+ {pokemons?.map((pokemon) => (
Enter fullscreen mode Exit fullscreen mode

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 ou undefined! ☝🤓

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.
Enter fullscreen mode Exit fullscreen mode

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>
);
Enter fullscreen mode Exit fullscreen mode

⚠️ 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>
);
Enter fullscreen mode Exit fullscreen mode

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(),
  };
});
Enter fullscreen mode Exit fullscreen mode

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>
);
Enter fullscreen mode Exit fullscreen mode

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>
);
Enter fullscreen mode Exit fullscreen mode

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

Top comments (14)

Collapse
 
lliw profile image
William Rodrigues

Muito bom o artigo, primo! Quem nunca passou por esses erros "bobos" ao mexer com React, até mesmo pessoas avançadas hein? Hahahaha

Collapse
 
m1guelsb profile image
Miguel Barbosa

Obrigado! Pois é, esquecer a propriedade key me acontece quase sempre!

Collapse
 
sandraoliv profile image
Sandraoliv

Muito bom de fato !
sou iniciante e confesso que já esbarrei nesses erros algumas vezes, foi bem esclarecedor!

Collapse
 
m1guelsb profile image
Miguel Barbosa

E faltou mais alguns na lista! Pensando em uma parte dois.

Collapse
 
phenriquesousa profile image
Pedro Henrique

Obrigado por compartilhar :)

Collapse
 
m1guelsb profile image
Miguel Barbosa

Tamo junto🫡

Collapse
 
proxy_go profile image
Proxy_go

Parabéns pelo artigo!

Collapse
 
m1guelsb profile image
Miguel Barbosa

Omg, thanks Proxy! 😊

Collapse
 
nikolai1312 profile image
Nicolas Evangelista

Conteúdo massa, primo! Mandou bem!

Collapse
 
m1guelsb profile image
Miguel Barbosa

Obrigado 🫡

Collapse
 
raulferreirasilva profile image
Raul Ferreira

Valeu pelo conteúdo, estou começando agora a programar em React, muito bom ver essas dicas, Muito obrigado 🦤.

Collapse
 
m1guelsb profile image
Miguel Barbosa

Fico feliz em ajudar, primo! 🫡

Collapse
 
marcelotk profile image
Marcelo Oliveira

{ !!pokemons.length && <PokemonList ...> }

Com "!!" você transforma o valor em Boolean, como o 0, em falsy, é false.

Collapse
 
m1guelsb profile image
Miguel Barbosa

Boa! Tem essa opção também, obrigado por compartilhar <3

Some comments have been hidden by the post's author - find out more