Entrada

⚛️ Conectar con API en React

En este artículo, aprenderemos a consumir una API usando React específicamente la API de Rick and Morty. Esta API es excelente para practicar, ya que es una API pública y gratuita, y devuelve información de personajes, episodios y ubicaciones de la serie animada.

Vamos a construir una pequeña app que liste los personajes y muestre su información. Todo desde cero.

Requisitos Previos

  • Tener instalado Node.js y npm o yarn.
  • Conocimientos básicos con los hooks useState y useEffect.

1. Crear el proyecto con Vite (recomendado)

Para crear un nuevo proyecto con una plantilla de React y configurado con TypeScript utilizando Vite, puedes usar el siguiente comando:

1
npm create vite@latest rick-and-morty-api -- --template react-ts

Una vez creado el proyecto, navegamos a la carpeta generada y ejecutamos el comando para instalar las dependencias:

1
2
cd rick-and-morty-api
npm install

Luego de forma opcional, inicia el servidor de desarrollo para ver la aplicación que nos crea vite:

1
npm run dev

React Vite StartApp React Vite StartApp

2. Estructura de Archivos

A pesar de que vite nos crea la estructura y la configuración, recomiendo organizar los archivos de la carpeta src de la siguiente manera:

1
2
3
4
5
6
7
8
9
10
src/
├── assets/
│   └── styles.css          # Estilos globales para los temas
├── components/
│   └── ToggleTheme.tsx     # Componente que cambia el tema
├── context/
│   └── ThemeContext.tsx    # Contexto para gestionar el tema
├── App.tsx                 # Componente principal de la aplicación
├── index.tsx               # Punto de entrada de la aplicación
└── index.css               # Estilos globales para la aplicación

3. Crear un hook personalizado

Ahora vamos a crear un hook personalizado llamado useRickAndMortyAPI, que nos permitirá consumir la API de manera reutilizable, y gestionar el estado de carga como los posibles errores.

Para ello, primero definiremos las interfaces necesarias para describir los datos que devuelve la API. Esta API nos entrega una lista de personajes junto con detalles como su nombre, especie e imagen, además de información sobre la paginación. Por lo tanto, vamos a tipar correctamente esa estructura para aprovechar las ventajas de TypeScript.

Creamos una nueva carpeta llamada hooks dentro de src/ y dentro de ella, cream un archivo useRickAndMortyAPI.ts y escribimos lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import { useState, useEffect } from 'react';
import axios from 'axios';

interface Character {
  id: number;
  name: string;
  image: string;
  species: string;
}

interface ApiResponse {
  results: Character[];
  info: {
    next: string | null;
  };
}

/**
 * Hook personalizado para consumir la API
 * @param url URL de la API
 * @returns characters (array), loading (boolean), error (string|null)
 */
const useRickAndMortyAPI = (url: string) => {
  const [characters, setCharacters] = useState<Character[]>([]);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const fetchCharacters = async () => {
      setLoading(true);
      try {
        const response = await axios.get<ApiResponse>(url);
        setCharacters(response.data.results);
        setLoading(false);
      } catch (err) {
        setError('Error fetching data');
        setLoading(false);
      }
    };

    fetchCharacters();
  }, [url]);

  return { characters, loading, error };
};

export default useRickAndMortyAPI;

Resumiendo el código anterior, tenemos lo siguiente:

  • Estados:
    • characters: Almacena los personajes obtenidos de la API.
    • loading: Indica si la petición aún esta en curso.
    • error: Almacena cualquier mensaje de error si la solicitud falla.
  • useEffect: Se usa para ejecutar la función fetchCharacters cuando el componente se monta o cuando la URL cambia (en este caso, cuando cambiamos la página de personajes).
  • axios.get: Se usa para realizar solicitudes HTTP a la API. El tipo de respuesta esperado es Apiresponse, que contiene una lista de personajes.

4. Usar el hook en un componente

A continuación, vamos a crear un componente llamado CharacterList, el cual utilizará el hook useRickAndMortyAPI para obtener y mostrar los personajes.

Crea un archivo CharacterList.tsx dentro de src/componentes, y escribimos el siguiente código para el componente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import React, { useState } from 'react';
import useRickAndMortyAPI from '../hooks/useRickAndMortyAPI';

const CharacterList: React.FC = () => {
  const [page, setPage] = useState(1);
  const { characters, loading, error } = useRickAndMortyAPI(
    `https://rickandmortyapi.com/api/character?page=${page}`
  );

  const handleNextPage = () => {
    setPage((prevPage) => prevPage + 1);
  };

  const handlePrevPage = () => {
    if (page > 1) setPage((prevPage) => prevPage - 1);
  };

  if (loading) return <div>Loading...</div>;
  if (error) return <div>{error}</div>;

  return (
    <div>
      <h1>Rick and Morty Characters</h1>
      <div className="pagination">
        <button onClick={handlePrevPage} disabled={page <= 1}>
          Anterior
        </button>
        <button onClick={handleNextPage}>
          Siguiente
        </button>
      </div>
      <div className="character-list">
        {characters.map((character) => (
          <div key={character.id} className="character-card">
            <img src={character.image} alt={character.name} />
            <h3>{character.name}</h3>
            <p>{character.species}</p>
          </div>
        ))}
      </div>
    </div>
  );
};

export default CharacterList;

Resumiendo el código anterior, tenemos lo siguiente:

URL Dependiente del Estado page

  • La URL que pasamos al hook useRickAndMortyAPI ahora incluye la variable page, lo que hace que la URL cambie cada vez que el valor de page cambie.
  • Como page está controlado con useState y el useEffect en el hook depende de la URL, el hook se ejecutará cada vez que el estado page cambie.

Actualización de la Páginación:

  • Cuando haces clic en el botón Anterior o Siguiente, decrementamos o incrementamos el valor de page, lo que también cambia la URl y hace que el hook se ejecute de nuevo.

5. Agregar estilos básicos

Para mejorar la apariencia de nuestra aplicación, podemos añadir algunos estilos simples. Vamos a editar o remplazar los estilos en src/App.css con los siguientes estilos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
.character-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 20px;
  margin-top: 20px;
}

.character-card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  width: 150px;
  text-align: center;
}

.character-card img {
  width: 100%;
  height: 150px;
  object-fit: cover;
}

.character-card h3 {
  font-size: 16px;
  margin: 10px 0;
}

.character-card p {
  font-size: 14px;
  color: gray;
}

.pagination {
  text-align: center;
  margin-top: 20px;
}

.pagination button {
  background-color: #2c3e50;
  color: white;
  border: none;
  padding: 10px;
  cursor: pointer;
  margin: 5px;
  border-radius: 5px;
}

.pagination button:disabled {
  background-color: #ccc;
}

6. Importar el componente en App.tsx

Finalmente, integramos todo en el componente App.tsx para mostrar la lista de personajes en pantalla.

Abre el archivo src/App.tsx y reemplaza su contenido con el siguiente:

1
2
3
4
5
6
7
8
import CharacterList from "./components/CharacterList";
import './App.css';

function App() {
  return <CharacterList />
}

export default App;

7. Repositorio

Pasa por el repositorio, ahí encontrarás el código completo por si quieres revisar la solución o clonarlo para experimentar por tu cuenta.

Cargando repositorio...

Si te interesa seguir mejorando esta app, podrías:

  • Agregar una barra de búsqueda por nombre.
  • Implementar filtros por especie o estado.
  • Usar React Router para ver el detalle de cada personaje.

¡El universo de Rick and Morty y el de React tienen mucho por explorar! 🚀

En este artículo construimos paso a paso una pequeña aplicación en React para consumir la API pública de Rick and Morty. Aprendimos a:

  • Crear un hook personalizado para centralizar la lógica de consumo de datos.
  • Usamos axios para hacer las peticiones HTTP de forma sencilla y elegante.
  • Manejar estados de carga y error de forma eficiente.
  • Utilizar paginación para navegar entre diferentes páginas de resultados.

Además, lo hicimos aprovechando el tipado de TypeScript y buenas prácticas.

Este tipo de ejercicios no solo nos ayuda a mejorar nuestras habilidades con React, sino también a escribir código limpio y reutilizable.

Esta entrada está licenciada bajo CC BY 4.0 por el autor.