5. Utiliser le Hook useHistory

Pour le moment, nous avons un problème dans notre application. En effet, depuis la fiche détaillée d’un pokémon, nous pouvons cliquer sur le bouton « Retour« , et atterrir sur la liste des pokémons. Mais une fois sur cette page, nous ne pouvons pas nous rendre sur la fiche détaillé d’un pokémon en cliquant dessus. Bref, nous ne pouvons naviguer que dans un sens.

Nous allons donc faire en sorte que lorsque l’on clique sur le composant PokemonCard, alors l’utilisateur est redirigé vers la page de détails d’un pokémon.

Pour faire cette redirection, nous n’allons pas utiliser la balise Link, car je souhaite vous montrer une autre façon de faire. À la place, nous allons utiliser un nouveau Hook, le Hook useHistory. 😎

Rendons-nous dans le composant PokemonCard, dans le fichier pokemon-card.tsx :

import React, { FunctionComponent, useState } from 'react';
import { useHistory } from 'react-router-dom';
import Pokemon from '../models/pokemon';
import formatDate from '../helpers/format-date';
import formatType from '../helpers/format-type';
import './pokemon-card.css';

type Props = {
  pokemon: Pokemon,
  borderColor?: string
};

const PokemonCard: FunctionComponent<Props> = ({pokemon, borderColor = '#009688'}) => {
 
  const [color, setColor] = useState<string>();
  const history = useHistory();
 
  const showBorder = () => {
    setColor(borderColor);
  };
 
  const hideBorder = () => {
    setColor('#f5f5f5');
  };

  const goToPokemon = (id: number) => {
    history.push(`/pokemons/${id}`);
  }
 
  return (
    <div className="col s6 m4" onMouseEnter={showBorder} onMouseLeave={hideBorder} onClick={() => goToPokemon(pokemon.id)}>
      <div className="card horizontal" style={{ borderColor: color }}>
        <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>{formatDate(pokemon.created)}</small></p>
            {pokemon.types.map(type => (
              <span key={type} className={formatType(type)}>{type}</span>
            ))}
          </div>
        </div>
      </div> 
    </div>
  );
}
 
export default PokemonCard;

Afin de mettre en place une redirection avec le Hook useHistory, nous avons ajouté plusieurs choses dans ce composant :

  • À la ligne 2, on importe tout simplement le hook useHistory depuis le paquet react-router-dom.
  • À la ligne 16, on récupère l’objet représentant l’historique du navigateur dans une variable history.
  • Ensuite, de la ligne 26 à 28, on implémente une nouvelle méthode de gestionnaire d’événement, qui prend en paramètre l’identifiant du pokémon vers lequel on souhaite effectuer une redirection. Pour cela, on utiliser la méthode push, et on lui passe en paramètre le chemin vers lequel on souhaite se rendre.
  • Enfin, à la ligne 31, on relie l’événement click à notre gestionnaire d’événement goToPokemon. Ainsi, le clic sur un pokémon déclenchera la navigation vers la fiche détaillée de ce pokémon.

Désormais, la navigation dans notre application est complète, et fonctionne correctement.

Mais du coup, quand est-ce qu’il faut utiliser l’élément Link, et quand utiliser le Hook useHistory ? 🤔

Et bien, comme nous l’avons, il s’agit de deux manières différentes de faire la même chose : une redirection. Cependant, le Hook useHistory est plus complet, car il nous donne accès à l’objet représentant l’historique du navigateur, ce qui nous aide à interagir facilement avec cet historique. Par exemple, la méthode history.goBack() permet de revenir facilement à la page précédente. En fonction de vos besoins ou de vos préférences, vous pouvez choisir la méthode qui vous convient le mieux. J’ai tendance à utiliser plutôt le hook useHistory, afin de déplacer la logique de mon code vers le composant plutôt que le template, mais c’est à vous de voir.

Je vous propose, pour terminer proprement, de gérer le cas où l’utilisateur souhaite accéder à une route qui n’existe pas dans notre application.