4. Passer une prop depuis le composant parent

Pour passer une prop, il nous faut au minimum un composant parent et un composant fils. Nous allons donc créer un composant parent, dans le dossier pages. Le composant parent PokemonList aura pour rôle d’afficher la liste de nos pokémons, et utilisera le composant PokemonCard pour gérer plus facilement l’affichage de chaque composant. Créez donc un nouveau fichier src/pages/pokemon-list.tsx :

import React, { FunctionComponent, useState, useEffect } from 'react';
import Pokemon from '../models/pokemon';
import POKEMONS from '../models/mock-pokemon';
import PokemonCard from '../components/pokemon-card';

const PokemonList: FunctionComponent = () => {
  const [pokemons, setPokemons] = useState<Pokemon[]>([]);

  useEffect(() => {
    setPokemons(POKEMONS);
  }, []);

  return (
    <div>
      <h1 className="center">Pokédex</h1>
      <div className="container"> 
        <div className="row"> 
        {pokemons.map(pokemon => (
          <PokemonCard key={pokemon.id} pokemon={pokemon}/>
        ))}
        </div>
      </div>
    </div> 
  );
}

export default PokemonList;

On remarque que à la ligne 19, on utilise le composant PokemonCard, en lui passant une prop représentant le pokémon à afficher. Ensuite, nous pouvons retournez dans notre composant App.tsx, afin de le décharger au maximum :

import React, { FunctionComponent } from 'react';
import PokemonsList from './pages/pokemon-list';

const App: FunctionComponent = () => {
  return (
  <PokemonsList />
  );
}

export default App;

Comme nous pouvons le voir à la ligne 6, ce composant ne fait que appeler le composant PokemonList. C’est exactement ce que nous voulons, car plus tard le composant App.tsx aura d’autres rôles, comme gérer la navigation dans notre application, et l’affichage d’une liste de pokémons revient au composant PokemonList, pas au composant principal de notre application.

Maintenant, si vous retournez dans votre application, vous devriez apercevoir la liste de pokémons suivante :

Notre application affiche une simple liste de pokémons.

Ce serait tout de même plus agréable d’afficher une jolie grille de pokémons, avec quelques images. Je vous propose donc de modifier le template du composant pokemon-card.tsx, comme ceci :

import React, { FunctionComponent } from 'react';
import Pokemon from '../models/pokemon';

type Props = {
  pokemon: Pokemon
};

const PokemonCard: FunctionComponent<Props> = ({pokemon}) => {
  
  return (
    <div className="col s6 m4">
      <div className="card horizontal">
        <div className="card-image"> 
          <img src={pokemon.picture} alt={pokemon.name}/>
        </div>
        <div className="card-stacked">
          <div className="card-content">
            <p>{pokemon.name}</p>
            <p><small>{pokemon.created.toString()}</small></p>
          </div>
        </div>
      </div> 
    </div>
  );
}

export default PokemonCard;

Avant de continuer, nous allons ajouter un peu de CSS pour nos futurs utilisateurs. Pour cela, créer un fichier pokemon-card.css (au même niveau d’arborescence que le fichier pokemon-card.tsx) :

.horizontal {
  border: solid 4px #f5f5f5;
  height: 200px;
}

On définit une bordure grise de 4 pixels de large pour tous nos pokémons, ainsi qu’une hauteur de 200 pixels, afin que toutes les cartes soient alignées.

Ensuite, il faut ajouter l’importation suivante dans notre composant pokemon-card.tsx :

import './pokemon-card.css'; // Ce code CSS sera appliqué uniquement au composant PokemonCard, grâce au ShadowDOM !

(Bien sûr, notre bordure grise sera masquée par la bordure par défaut que nous avons définies plus haut. Nous faisons cela car prochainement nous allons utiliser cette couleur par défaut définis dans le CSS).

Et voilà, retournez dans votre application. Je vous laisse admirer le résultat. 😎