Erros comuns de iniciantes em ReactJS

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
  • 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:

 style="height: 3rem; background-color: blue;">
  A really cool 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 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.

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

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post
announcing:-the-local-business-content-marketing-guide

Announcing: The Local Business Content Marketing Guide

Next Post
the-amazing-benefits-of-journalistic-content-(plus-7-pro-tips-you-can-use-today!)

The Amazing Benefits of Journalistic Content (Plus 7 Pro Tips You Can Use Today!)

Related Posts