No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Peticiones asíncronas

12/22
Recursos

Aportes 35

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Adjunto mi respuesta

Seria un poco mejor pasar la logica de consulta de los detalles a al componente de PokemonCard. Eso evitaria el uso de Promise.all() el paso excesivo de parametros del componente padre al hijo y ademas seria un poco mas eficiente

Adjunto mi respuesta ingresando todos los datos y haciendo uso del método join

Promise.all()



Es un metodo estatico de la clase Promise que toma como input un array de promesas y devuelve como resultado un array con los resultados de las promesas resueltas en el orden en que fueron agregadas en el input.

Devuelve los resultados una vez todas las promesas sean resueltas. Si una de ellas falla el Promise.all rechazara la operación.

Este ejemplo lo saque del confiable MDN Web Docs, por lo que si quieres una explicación más a fondo ve para alla:

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

Para el desafío, desde el componente PokemonList pase las habilidades por props a el componente PokemonCard

const PokemonList = ({ pokemons })=> {
   
    return (
        <div className="PokemonList">
            {
                pokemons.map(pokemon => (
                    <PokemonCard name={pokemon.name} key={pokemon.name} image={pokemon.sprites.front_default} abilities={pokemon.abilities} /> // **
                ))
            }
        </div>
    )
}

desde el componente PokemonCard recibí y desestructure todas las props, al ser un arreglo lo que recibe en la prop de las habilidades, cree la lógica para poder iterar sobre cada elemento de este arreglo y presentar el nombre de cada habilidad en forma de lista de manera dinámica

const PokemonCard = ({ name, image, abilities })=> {

    return (
        <Card 
            ....
        >
            <Meta description={<ul>
                {abilities.map(ability => <li key={ability.ability.name} >{ability.ability.name}</li>)}
            </ul>} 
            />
        </Card>
    )
}

este fue el resultado:

Hay algo realmente molesto con este curso, al menos a mí me lo parece; el texto está muy chiquito, te toca poner pantalla completa para poder ver :c

Mi aporte con el reto de las habilidades y también agregue los tipos. Ademas agregue una etiqueta de color por cada tipo de pokemon.
.

.
PokemonCard

import React from 'react'
import { Card, Badge } from 'flowbite-react';
import { FiHeart } from "react-icons/fi";

function PokemonCard(props) {

  const typeToColorClass = {
    bug: "bg-lime-100 text-lime-900 dark:bg-lime-900 dark:text-lime-300",
    dark: "bg-gray-200 text-white dark:bg-gray-400 dark:text-gray-900",
    dragon: "bg-indigo-200 text-indigo-900 dark:bg-indigo-700 dark:text-indigo-200",
    electric: "bg-yellow-200 text-black dark:bg-yellow-600 dark:text-yellow-100",
    fairy: "bg-pink-200 text-pink-900 dark:bg-pink-800 dark:text-pink-100",
    fighting: "bg-red-400 text-white dark:bg-red-600 dark:text-red-100",
    fire: "bg-red-200 text-red-800 dark:bg-red-900 dark:text-red-100",
    flying: "bg-teal-100 text-teal-700 dark:bg-teal-700 dark:text-teal-100",
    ghost: "bg-purple-300 text-white dark:bg-purple-700 dark:text-purple-200",
    grass: "bg-green-100 text-green-800 dark:bg-green-700 dark:text-green-200",
    ground: "bg-amber-900 text-white dark:bg-amber-600 dark:text-brown-100",
    ice: "bg-cyan-100 text-cyan-900 dark:bg-lightblue-700 dark:text-lightblue-100",
    normal: "bg-gray-300 text-black dark:bg-gray-500 dark:text-gray-100",
    poison: "bg-purple-200 text-purple-900 dark:bg-purple-700 dark:text-purple-200",
    psychic: "bg-pink-200 text-pink-900 dark:bg-pink-600 dark:text-pink-100",
    rock: "bg-slate-300 text-slate-900 dark:bg-amber-500 dark:text-brown-100",
    steel: "bg-gray-400 text-black dark:bg-gray-600 dark:text-gray-200",
    water: "bg-blue-200 text-blue-900 dark:bg-blue-800 dark:text-blue-100"
  };

  return (
    
    <Card 
      className=''
      imgAlt={props.name}
      imgSrc={props.image}
    >
      <h1 className="text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
        {`${props.index} - ${props.name}`}
      </h1>
      <Badge className="bg-red-100 text-red-800 text-xs font-bold mr-2 px-2.5 py-0.5 rounded dark:bg-red-900 dark:text-red-300">
        ID: {props.id}
      </Badge>

      <h2>Type: </h2>
      <p>
        {props.types.map(object => {
          const colorClass = typeToColorClass[object.type.name] || typeToColorClass.default;

          return (
            <span
              key={object.type.name}
              className={`text-md font-bold mr-2 px-3.5 py-2 rounded ${colorClass}`}
            >
              {object.type.name}
            </span>
          )
        })}
      </p>

      <h3 className='font-bold'>Abilities: </h3>
      <p className="font-normal text-gray-700 dark:text-gray-400">
        {props.abilities.map(object => (
          <li
            key={object.ability.name}
          > {object.ability.name} </li>
        )
        )}
      </p>
      <button>
        <FiHeart/>
      </button>
    </Card>
  )
}

export { PokemonCard }

PokemonList.jsx

import React from 'react'
import { PokemonCard } from '../PokemonCard'
import { v4 as uuidv4 } from 'uuid';


function PokemonList({ pokemons }) {

  // console.log('file: PokemonList.jsx | Line 8: ',pokemons)

  return (
    <div className='PokemonList grid grid-cols-4 gap-4 flex-col w-full m-10 '>
      {pokemons.map((pokemon, index) => {

        const id = uuidv4();

        return <PokemonCard 
          key={index}
          id={id}
          index={index}
          name={pokemon.name}
          image={pokemon.sprites.front_default}
          abilities={pokemon.abilities}
          types={pokemon.types}
        />
      })}
    </div>
  )
}

PokemonList.defaultProps = {
  pokemons : Array(10).fill('') // [''],[''],[''], ...x10
}

export { PokemonList }

.
API

import axios from 'axios'

const API_URL = 'https://pokeapi.co/api/v2/pokemon?limit=151'

export const getPokemon = async () => {
  return axios 
  .get(API_URL)
  .then((res) => res.data.results)
  .catch((err) => console.log(err))
}

export const getPokemonDetails = (pokemon) => {
  return axios.get(pokemon.url)
  .then(res => res.data)
  .catch((err) => console.log(err))
}

LO LOGREEEEEEEE

Yo saqué los nombres de habilidades desde el componente PokelmonList

export default function PokemonList() {
  const pokemons = useSelector(state => state.pokemons)

  return (
    <div className="PokemonList">
      {pokemons.map((pokemon) => {
        let abilities = pokemon.abilities.map(ability => ability.ability.name).join(', ')
        
        return <PokemonCard
          name={pokemon.name}
          key={pokemon.name}
          img={pokemon.sprites.front_default}
          abilities={abilities} />
      })}
    </div>
  )
}

pdta: si, ability.ability es absurdo, creo que muchas veces uno pierde mucho tiempo por no ver bien cómo vienen las propiedades de los objetos, que a veces son absurdas pero pues es lo que hay :'v

Ahí hago uso del useSelector que sería acceder al store del redux, porque sino estamos haciendo uso de los props entonces daría igual usar redux (para mi), no entiendo por qué la profe no lo hace :p

Esta clase estuvo algo desafiante:

  • Por un lado tuve problemas con el devtools de redux, lo arregle reiniciando la extension en el navegador
  • El hecho de usar TS jajajaja. Aun soy nuevo, decidi que era un buen momento para practicar. Si ven algo que mejorar lo comentan.

Dejo mi código para otros viajeros que se atrevieron a seguir esta senda: Estoy dejando todo el codigo que tuve que modificar , por eso el numero de archivos.

import { FC } from "react";
import { PokemonDetailType } from "../api";
import { PokemonCard } from "./PokemonCard";
import './PokemonList.css'

interface Props {
    pokemons: PokemonDetailType[]
}

const PokemonList:FC<Props> = ({ pokemons }) =>{
    return (
        <div className="PokemonList">
            {pokemons.map((pokemon,index)=>(
                <PokemonCard 
                    name={pokemon.name} 
                    types={pokemon.types} 
                    image={pokemon.sprites.other.home.front_default}  
                    key={pokemon.name} 
                />
            ))}
        </div>
    )
}

PokemonList.defaultProps = {
    pokemons: Array(10).fill('')
}

export {
    PokemonList
}
import { FC } from "react";
import { StarOutlined } from "@ant-design/icons";
import { Card } from "antd";
import Meta from "antd/lib/card/Meta";

type Props = {
    name: string,
    image: string,
    types: any[]
}

const PokemonCard:FC<Props> = ({name, image, types}) => {
    return (
        <Card
            title={name}
            cover={<img src={image} alt={name} />}
            extra={<StarOutlined />}
        >
            <Meta description={types.map(type=>type.type.name).join()} />
        </Card>
    )
}

export {
    PokemonCard
}
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Search } from './components/Search'
import { PokemonList } from './components/PokemonList'
import { Col } from 'antd'
import { getPokemonDetails, getPokemons, PokemonType } from './api'
import { setPokemons } from './actions'
import { TypeState } from './reducers/pokemon'
import logo from './statics/logo.svg'
import './App.css'

function App() {
  const pokemons = useSelector((state:TypeState)=>state.pokemons)
  const dispath = useDispatch();
  useEffect(()=>{
    async function fetchPokemon(){
        const pkmns = await getPokemons();
        const pkmnsDetailed = await Promise.all((pkmns as PokemonType[]).map(pkmn=>getPokemonDetails(pkmn)))
        dispath(setPokemons(pkmnsDetailed))
    } 
    fetchPokemon();
  },[])
  return (
    <div className="App">
      <Col span={4} offset={10}>
        <img src={logo} alt="Pokedux" />
      </Col>
      <Col span={8} offset={8}>
        <Search />
      </Col>
      <PokemonList pokemons={pokemons} />
    </div>
  )
}


export default App;

import { PokemonDetailType, PokemonType } from "../api";
import { SET_POKEMONS } from "./types";


export const setPokemons = (payload: PokemonDetailType[])=>({
    type: SET_POKEMONS,
    payload
})
import { PokemonDetailType, PokemonType } from "../api";
import { SET_POKEMONS } from "./types";


export const setPokemons = (payload: PokemonDetailType[])=>({
    type: SET_POKEMONS,
    payload
})
import { SET_POKEMONS } from "../actions/types"
import { PokemonDetailType } from "../api"

export type TypeState = {
    pokemons: PokemonDetailType[]
}

const initialState: TypeState = {
    pokemons: []
}

export const pokemonReducer = (state:TypeState = initialState, action:any)=>{
    switch(action.type){
        case SET_POKEMONS:
            return {...state, pokemons: action.payload}

        default:
            return state
    }

}

Mi seguimiento con TypeScript. He tenido que cambiar varias cosas dentro del código, pero quedó mucho mejor y entendible para todos. Recibo sus comentarios y espero que ayude a quién lo pueda necesitar.

.

// index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { pokemonsReducer } from './reducers/pokemons';
import { Provider } from 'react-redux';
import { applyMiddleware, compose, legacy_createStore as createStore } from 'redux';
import { logger } from './middlewares';
import './index.css';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);

const composedEnhancers = compose(
  applyMiddleware(logger),
  (window as any).__REDUX_DEVTOOLS_EXTENSION__ && (window as any).__REDUX_DEVTOOLS_EXTENSION__(),
)

const store = createStore(pokemonsReducer, composedEnhancers);

root.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>
);

.

// App.tsx

import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Col } from "antd";
import Searcher from "./components/Searcher";
import PokemonList from "./components/PokemonList";
import { getPokemon, getPokemonDetails } from "./api";
import { setPokemonsDetails } from "./actions";
import { IPokemonDetails } from "./types";

import logo from "./statics/logo.svg";
import "./App.css";

type AppType = {
  pokemons: IPokemonDetails[];
};

function App() {
  const pokemons = useSelector((state: AppType) => state.pokemons);
  const dispatch = useDispatch();

  useEffect(() => {
    const fetchPokemons = async () => {
      const response = await getPokemon();

      if (response) {
        const pokemonsDetails = await Promise.all(
          response.map((pokemon) => getPokemonDetails(pokemon))
        );
        dispatch(setPokemonsDetails(pokemonsDetails));
      }
    };
    fetchPokemons();
  }, [dispatch]);

  return (
    <div className="App">
      <Col span={4} offset={10}>
        <img src={logo} alt="Pokedux" />
      </Col>
      <Col span={8} offset={8}>
        <Searcher />
      </Col>
      <PokemonList pokemons={pokemons} />
    </div>
  );
}

export default App;

.

// types/index.ts

export interface IPokemonDetails {
  abilities:                [];
  // base_experience:          number;
  // forms:                    [];
  // game_indices:             [];
  // height:                   number;
  // held_items:               any[];
  // id:                       number;
  // is_default:               boolean;
  // location_area_encounters: string;
  // moves:                    [];
  name: string;
  // order:                    number;
  // past_types:               any[];
  // species:                  [];
  sprites: SpritesType;
  // stats:                    [];
  // types:                    [];
  // weight:                   number;
}

export interface IPokemonType {
  name: string;
  url: string;
}

export type InitialPokemonsStateType = {
  pokemons: IPokemonType[];
};

export type SpritesType = {
  back_default: string;
  back_female: string | null;
  back_shiny: string;
  back_shiny_female: string | null;
  front_default: string;
  front_female: string | null;
  front_shiny: string;
  front_shiny_female: string | null;
};

.

// api/responses/index.ts

import { IPokemonType } from "../../types";

export type PokemonResponseType = {
  results: IPokemonType[];
};



// api/index.ts

import axios from "axios";
import { IPokemonDetails } from "../types";
import { PokemonResponseType } from "./responses";

export const getPokemon = async () => {
  const URL = "https://pokeapi.co/api/v2/pokemon?limit=151";
  try {
    const { data } = await axios.get<PokemonResponseType>(URL);
    const { results } = data;
    return results;
  } catch (err) {
    console.error("err ".repeat(5), err);
  }
};

export const getPokemonDetails = async (pokemon: any) => {
  try {
    const { data } = await axios.get<IPokemonDetails>(pokemon.url);
    return data;
  } catch (err) {
    console.error("err ".repeat(5), err);
  }
};

.

// reducers/pokemons.ts

import { SET_POKEMONS_DETAILS } from "../actions/types";
import { InitialPokemonsStateType } from "../types";

const initialState: InitialPokemonsStateType = {
  pokemons: [],
};

export const pokemonsReducer = (
  state: InitialPokemonsStateType = initialState,
  action: any
) => {
  switch (action.type) {
    case SET_POKEMONS_DETAILS:
      return {
        ...state,
        pokemons: action.payload,
      };

    default:
      return state;
  }
};

.

// components/PokemonList

import React from "react";
import { IPokemonDetails } from "../types";
import PokemonCard from "./PokemonCard";
import "./PokemonList.css";

type PokemonListProps = {
  pokemons: (IPokemonDetails | undefined)[];
};

const PokemonList = (props: PokemonListProps) => {
  return (
    <div className="PokemonList">
      {props.pokemons.map(
        (pokemon) =>
          pokemon && <PokemonCard key={pokemon.name} pokemon={pokemon} />
      )}
    </div>
  );
};

export default PokemonList;



// components/pokemonCard.tsx

import React from "react";
import { Card } from "antd";
import Meta from "antd/lib/card/Meta";
import { StarOutlined } from "@ant-design/icons";
import { IPokemonDetails } from "../types";

type PokemonCardProps = {
  pokemon: IPokemonDetails;
};

const PokemonCard = (props: PokemonCardProps) => {
  return (
    <Card
      style={{ width: 250 }}
      title={props.pokemon.name}
      cover={<img src={props.pokemon.sprites.front_default} alt={props.pokemon.name} />}
      extra={<StarOutlined />}
    >
      <Meta description="fire, magic" />
    </Card>
  );
};

export default PokemonCard;

Adjunto el ejercicio incluidas las habilidades de cada pokemon, como buena practica, es recomendable separar la lógica (reduce, maps, condicionales) de las vistas jsx en archivos separados comúnmente llamados customHooks

https://github.com/fsiatama/pokedux/tree/feature/redux-devtools

No se si sea la mejor forma pero se ve bien en la UI. ![](https://static.platzi.com/media/user_upload/image-53ce871d-2c58-49d7-8112-9d11d0adf9fb.jpg)
Yo decidí mostrar los tipos de cada pokemon como información extra. Acá mi código (humildemente): ![](https://ibb.co/qn5MxS0)
Yo decidí mostrar los tipos de cada pokemon como información extra. Acá mi código (humildemente):const PokemonList = ({ pokemons }) => { ```js const PokemonList = ({ pokemons }) => { return (
{pokemons.map((pokemon) => { return <PokemonCard name={pokemon.name} image={pokemon.sprites.front_default} types={pokemon.types} key={pokemon.name} /> })}
); } const PokemonCard = ({ name, image, types }) => { const renderTypes = () => { return types.map(type => type.type.name).join(', '); } return <Card title={name} cover={<img src={image} alt={name} />} extra={<StarOutlined />} > <Meta description={renderTypes}></Meta> </Card> } ``` return ( \
{pokemons.map((pokemon) => { return \<PokemonCard name={pokemon.name} image={pokemon.sprites.front\_default} types={pokemon.types} key={pokemon.name} /> })} \
); } const PokemonCard = ({ name, image, types }) => { const renderTypes = () => { return types.map(type => type.type.name).join(', '); } return \<Card title={name} cover={\<img src={image} alt={name} />} extra={\<StarOutlined />} \> \<Meta description={renderTypes}>\</Meta> \</Card> }
Yo decidí mostrar los tipos de cada pokemon como información extra. Acá mi código (humildemente): ```js const PokemonList = ({ pokemons }) => { return (
{pokemons.map((pokemon) => { return <PokemonCard name={pokemon.name} image={pokemon.sprites.front_default} types={pokemon.types} key={pokemon.name} /> })}
); } const PokemonCard = ({ name, image, types }) => { const renderTypes = () => { return types.map(type => type.type.name).join(', '); } return <Card title={name} cover={<img src={image} alt={name} />} extra={<StarOutlined />} > <Meta description={renderTypes}></Meta> </Card> } ```const PokemonList = ({ pokemons }) => { return ( \
{pokemons.map((pokemon) => { return \<PokemonCard name={pokemon.name} image={pokemon.sprites.front\_default} types={pokemon.types} key={pokemon.name} /> })} \
); }
Yo decidí mostrar los tipos de cada pokemon como información extra. Acá mi código (humildemente): ```js const PokemonCard = ({ name, image, types }) => { const renderTypes = () => { return types.map(type => type.type.name).join(', '); } return <Card title={name} cover={<img src={image} alt={name} />} extra={<StarOutlined />} > <Meta description={renderTypes}></Meta> </Card> } ``````js const PokemonList = ({ pokemons }) => { return (
{pokemons.map((pokemon) => { return <PokemonCard name={pokemon.name} image={pokemon.sprites.front_default} types={pokemon.types} key={pokemon.name} /> })}
); } ```
Yo decidí poner los tipos como información adicional en las tarjetas. Acá dejo mi código:const PokemonCard = ({ name, image, types }) => {    const renderTypes = () => {        return types.map(type => type.type.name).join(', ');    }     return \<Card        title={name}        cover={\<img src={image} alt={name} />}        extra={\<StarOutlined />}    >        \<Meta description={renderTypes}>\</Meta>    \</Card>} ![]()```js const PokemonCard = ({ name, image, types }) => { const renderTypes = () => { return types.map(type => type.type.name).join(', '); } return <Card title={name} cover={<img src={image} alt={name} />} extra={<StarOutlined />} > <Meta description={renderTypes}></Meta> </Card> } ```
corrijo un error que tenia ![](https://static.platzi.com/media/user_upload/image-3a3b58e0-5f54-4475-b003-d25055fd4f6e.jpg)
adjunto mi solución ![](https://static.platzi.com/media/user_upload/image-43cb2105-24ab-4371-ab82-d965913b3a19.jpg)
resuelto :) ![]()![]()![]()```js const PokemonCard = ({name, image, abilities}) => { return <Card title= {name} cover= {<img src={image} alt= {name} />} extra={<StarOutlined/>} > <Meta description= {abilities} /> </Card> } export default PokemonCard; ``````js const PokemonList = ({pokemons}) => { return(
{pokemons.map((pokemon) => { return <PokemonCard name={pokemon.name} key={pokemon.name} image= {pokemon.sprites.front_default} abilities={pokemon.abilities.map((ability) => ability.ability.name).join(", ")}/> })}
) }; PokemonList.defaultProps = { pokemons: Array(10).fill(''), }; export default PokemonList; ```

Mi solución c:
PokemonList

<div className='PokemonList'>
      {pokemons.map((pokemon) => {
        const abilitiesArray = pokemon.types;
        const abilities = abilitiesArray.map((ability) => ability.type.name);
        
        return <PokemonCard name={pokemon.name} imagen={pokemon.sprites.front_default} abilities={abilities} key={pokemon.name} />;
      })}
    </div>

PokemonCard

<Meta description={abilities.length > 1 ? `${abilities[0]}, ${abilities[1]}` : abilities[0] } />

Si en PokemonList en lugar de poner image={pokemon.sprites.front_default} ponen:

image={pokemon.sprites.other["official-artwork"].front_default}

cambia la imagen a una no pixeleada

Es normal que la carga de todos los data se tarde, como se mejora el performance, para hacer una mejor UX.

Dejo mi solución por acá:

src>components>PokemonList.jsx

import React from 'react'
import PokemonCard from '../PokemonCard'

function PokemonList({ pokemons }) {
  return (
    <div className='PokemonList'>
        {pokemons.map(
            (pokemon)=>(<PokemonCard
                          name={pokemon.name}
                          key={pokemon.name}
                          image={pokemon.sprites.front_default}
                          abilities={pokemon.abilities}
                          />)
        )}
    </div>
  )
}

export default PokemonList

src>components>PokemonCard.jsx

import React from 'react'
import {Card} from 'antd'
import Meta from 'antd/lib/card/Meta'
import {StarOutlined} from '@ant-design/icons'
import './PokemonList/PokemonList.css'

function PokemonCard({ name, image, abilities }) {
  return (
    <Card
        title={name}
        cover={<img
          src={image}
          alt={name}
          />}
        extra={<StarOutlined/>}
    >
        <Meta description={abilities
                              .filter(ability => (!ability.is_hidden))
                              .map(ability => (ability.ability.name))
                              .join(', ')
                            }
        />
    </Card>
  )
}

export default PokemonCard

Se está tomando en cuenta si la habilidad está oculta o no.

Para el que quiere ver como se hace la peticion utilizando las promesas.

useEffect(() => {
    getPokemons()
      .then((res) => res.results) // retorna el array de pokemons
      .then((res) => {
        // hacemos un promise All para que por cada pokemon haga una peticion al backend sobre sus detalles
        Promise.all(
          res.map((pokemon) =>
            getPokemonDetails(pokemon.url).then((res) => res)
          )
        ).then((res) => dispatch(setPokemons(res)));
        // una vez terminadas todas nuestras promesas hacemos el dispatch
      })
      .catch((err) => dispatch(setError(err)));
  }, []);

Mi solución fué:

import PokemonCard from "./PokemonCard";

const PokemonList = ({ pokemons }) => {
  return (
    <div className="PokemonList">
      {pokemons.map((pokemon) => {
        return (
          <PokemonCard
            name={pokemon.name}
            key={pokemon.name}
            image={pokemon.sprites.front_default}
            abilities={pokemon.abilities[0].ability.name}
          />
        );
      })}
    </div>
  );
};

PokemonList.defaultProps = {
  pokemons: Array(8).fill(""),
};

export default PokemonList;

No fue lo más óptimo, pero fue lo que me salió 😅

Al momento de traer la imagen de los pokemons, con este codigo traes un svg que se ve mas definido.

 <div className="PokemonList">
        {pokemons.map((pokemon, index) => {
            return <PokemonCard key={id + index} name={pokemon.name} image={pokemon?.sprites?.other?.dream_world?.front_default}/>
        })}
    </div>

Hice esto pero con los tipos de pokemones:

archivo PokemonList.jsx
Hice una función q hace un map por cada abilities, retorna las habilidades separadas por un guion

const pokemonsAbilities = abilities.map(ability => ability.ability.name);
  // utilizando ListFormat
  const formatAbilities = new Intl.ListFormat('es').format(pokemonsAbilities);
  // como estamos indicando el idioma en español('es') aparece
  // la conjunción "y", si fuera inglés aparecería "and"
  // output por cada pokemon(pidgeot) => keen-eye, tangled-feet y big-pecks
  // output por cada pokemon(pidgeot) => keen-eye, tangled-feet, and big-pecks
<Meta description={formatAbilities} />

archivo PokemonList.jsx
pase las habilidades como props

archivo PokemonCard.jsx
Hice un map por cada habilidad dentro de abilities

asi me quedo finalmente, para poner la description, me ayude con el codigo de Fabian, porque no sabia como llegar hasta las abilidades por la parte del codigo