Hey salut, bienvenue dans ce tutoriel. Nous allons ensemble créer notre propre composant Modal en utilisant un hooks personnel. Tu peux voir la version finale de ce que nous allons créer sur ce lien.

Créer un hook personnel

Nous allons donc commencer par créer un hooks pour gérer l'état de notre composant Modal. Nous allons créer un fichier useModal.js et y mettre le contenu suivant:

import { useState } from "react";

const useModal = () => {
  const [isShowing, setIsShowing] = useState(false);

  function toggle() {
    setIsShowing(!isShowing);
  }

  return {
    isShowing,
    toggle
  };
};

export default useModal;

Ce que nous faisons ici est plutôt simple au fait, nous initialisons un état isShowing à false et une fonction setIsShowing pour changer sa valeur avec useState de React, ensuite nous définissons une fonction toggle qui permet de changer la valeur de isShowing à true ou false et enfin nous retournons l'état isShowing et la fonction toggle. Nous pouvons maintenant définir notre composant Modal.

Définir le composant Modal

Pour créer le composant, nous allons créer un fichier modal.js et y mettre le contenu suivant:

import React from "react";
import ReactDOM from "react-dom";

const Modal = ({ isShowing, hide }) =>
  isShowing
    ? ReactDOM.createPortal(
        <>
          <div className="modal-overlay">
            <div className="modal-wrapper">
              <div className="modal">
                <div className="modal-header">
                  <h4>Modal Header</h4>
                  <button
                    type="button"
                    className="modal-close-button"
                    onClick={hide}
                  >
                    <span>&times;</span>
                  </button>
                </div>
                <div className="modal-body">Hello Modal Here</div>
              </div>
            </div>
          </div>
        </>,
        document.body
      )
    : null;

export default Modal;

Le composant prend deux paramètres (props), isShowing qui est un booléen et hide une fonction. Le contenu du modal n'est afficher que si isShowing vaut true, si c'est le cas, on crée un portal dans lequel on affiche le modal.

Alors un Portal c'est quoi? Les portals en React permettent d'afficher un composant dans le DOM en dehors de son composant parent.

Disons que nous avons bouton qui doit enclencher notre composant Modal et que ce bouton est défini dans la barre de navigation, si nous n'utilisons pas un portal, notre Modal sera rendu dans la barre de navigation, et nous ne voulons pas de cela.

Nous utilisons donc ReactDOM.createPortal() en lui envoyant comme premier paramètre le composant à afficher et comme deuxième paramètre l'emplacement où afficher le composant, à la fin de la balise body dans notre cas.

Nous allons juste apporter un peu de CSS à notre composant Modal, je vais utiliser styled-jsx pour celà. Voici donc le nouveau fichier modal.js:

import React from "react";
import ReactDOM from "react-dom";

const Modal = ({ isShowing, hide }) =>
  isShowing
    ? ReactDOM.createPortal(
        <>
          <div className="modal-overlay">
            <div className="modal-wrapper">
              <div className="modal">
                <div className="modal-header">
                  <h4>Modal Header</h4>
                  <button
                    type="button"
                    className="modal-close-button"
                    onClick={hide}
                  >
                    <span>&times;</span>
                  </button>
                </div>
                <div className="modal-body">Hello Modal Here</div>
              </div>
            </div>
          </div>

          <style jsx="true">{`
            .modal-overlay {
              position: fixed;
              top: 0;
              left: 0;
              width: 100vw;
              height: 100vh;
              z-index: 1040;
              background-color: rgba(0, 0, 0, 0.5);
            }

            .modal-wrapper {
              position: fixed;
              top: 0;
              left: 0;
              z-index: 1050;
              width: 100%;
              height: 100%;
              overflow-x: hidden;
              overflow-y: auto;
              outline: 0;
              display: flex;
              align-items: center;
            }

            .modal {
              z-index: 100;
              background: #fff;
              position: relative;
              margin: auto;
              border-radius: 5px;
              max-width: 500px;
              width: 80%;
              padding: 1rem;
            }

            .modal-header {
              display: flex;
              justify-content: space-between;
              align-items: center;
            }

            .modal-close-button {
              font-size: 1.4rem;
              font-weight: 700;
              color: #000;
              cursor: pointer;
              border: none;
              background: transparent;
            }
          `}</style>
        </>,
        document.body
      )
    : null;

export default Modal;

Nous pouvons maintenant utiliser notre composant Modal, rendez-vous donc dans le fichier App.js et mettez-y le contenu suivant:

import React from "react";
import useModal from "./useModal";
import Modal from "./modal";

export default function App() {
  const { isShowing, toggle } = useModal();

  return (
    <>
      <div className="App">
        <button className="modal-toggle" onClick={toggle}>
          Show modal
        </button>

        <Modal isShowing={isShowing} hide={toggle} />
      </div>

      <style jsx="true">{`
        .App {
          height: 100vh;
          display: flex;
          justify-content: center;
          align-items: center;
        }

        button.modal-toggle {
          background-color: turquoise;
          cursor: pointer;
          padding: 1rem 2rem;
          text-transform: uppercase;
          border: none;
        }
      `}</style>
    </>
  );
}

Nous utilisons le hooks useModal() que nous avons créé récemment, et après tout ce que nous faisons, nous avons un bouton qui appelle la méthode toggle() quand on clique dessus, cette fonction change juste la valeur de isShowing a true ou false, puis nous appelons notre composant Modal en lui envoyant isShowing et toggle. Voilà, nous avons un composant Modal qui marche bien.

Nous allons juste modifier notre composant pour marcher avec n'importe quel contenu, disons que nous voulons afficher un formulaire de connexion et d'inscription avec le même composant.

Notre fichier modal.js:

import React from "react";
import ReactDOM from "react-dom";
import PropTypes from "prop-types";

const Modal = ({ isShowing, hide, title, ...props }) =>
  isShowing
    ? ReactDOM.createPortal(
        <>
          <div className="modal-overlay">
            <div className="modal-wrapper">
              <div className="modal">
                <div className="modal-header">
                  <h4>{title}</h4>
                  <button
                    type="button"
                    className="modal-close-button"
                    onClick={hide}
                  >
                    <span>&times;</span>
                  </button>
                </div>
                <div className="modal-body">{props.children}</div>
              </div>
            </div>
          </div>

          <style jsx="true">{`
            .modal-overlay {
              position: fixed;
              top: 0;
              left: 0;
              width: 100vw;
              height: 100vh;
              z-index: 1040;
              background-color: rgba(0, 0, 0, 0.5);
            }

            .modal-wrapper {
              position: fixed;
              top: 0;
              left: 0;
              z-index: 1050;
              width: 100%;
              height: 100%;
              overflow-x: hidden;
              overflow-y: auto;
              outline: 0;
              display: flex;
              align-items: center;
            }

            .modal {
              z-index: 100;
              background: #fff;
              position: relative;
              margin: auto;
              border-radius: 5px;
              max-width: 500px;
              width: 80%;
              padding: 1rem;
            }

            .modal-header {
              display: flex;
              justify-content: space-between;
              align-items: center;
            }

            .modal-close-button {
              font-size: 1.4rem;
              font-weight: 700;
              color: #000;
              cursor: pointer;
              border: none;
              background: transparent;
            }
          `}</style>
        </>,
        document.body
      )
    : null;

Modal.propTypes = {
  isShowing: PropTypes.bool.isRequired,
  hide: PropTypes.func.isRequired,
  title: PropTypes.string.isRequired
};

export default Modal;

Et le fichier App.js:

import React from "react";
import useModal from "./useModal";
import Modal from "./modal";

export default function App() {
  const { isShowing: isLoginFormShowed, toggle: toggleLoginForm } = useModal();
  const {
    isShowing: isRegistrationFormShowed,
    toggle: toggleRegistrationForm
  } = useModal();

  return (
    <>
      <div className="App">
        <button className="modal-toggle" onClick={toggleLoginForm}>
          Login
        </button>
        <button className="modal-toggle" onClick={toggleRegistrationForm}>
          Register
        </button>

        <Modal
          isShowing={isLoginFormShowed}
          hide={toggleLoginForm}
          title="Login"
        >
          <form>
            <div className="form-group">
              <input type="text" placeholder="Username" />
            </div>
            <div className="form-group">
              <input type="text" placeholder="Password" />
            </div>
            <div className="form-group">
              <input type="submit" value="Login" />
            </div>
          </form>
        </Modal>

        <Modal
          isShowing={isRegistrationFormShowed}
          hide={toggleRegistrationForm}
          title="Register"
        >
          <form>
            <div className="form-group">
              <input type="text" placeholder="Email Address" />
            </div>
            <div className="form-group">
              <input type="text" placeholder="Username" />
            </div>
            <div className="form-group">
              <input type="text" placeholder="Password" />
            </div>
            <div className="form-group">
              <input type="submit" value="Register" />
            </div>
          </form>
        </Modal>
      </div>

      <style jsx="true">{`
        .App {
          height: 100vh;
          display: flex;
          justify-content: center;
          align-items: center;
        }

        button.modal-toggle,
        input[type="submit"] {
          background-color: turquoise;
          cursor: pointer;
          padding: 1rem 2rem;
          text-transform: uppercase;
          border: none;
        }

        button.modal-toggle:not(:first-child) {
          margin-left: 10px;
        }

        .form-group {
          margin-top: 10px;
        }

        input[type="text"],
        input[type="password"],
        input[type="email"] {
          box-sizing: border-box;
          width: 100%;
          padding: 0.5rem 0.7rem;
        }
      `}</style>
    </>
  );
}

Ça y est, vous pouvez maintenant créer autant de modal que vous le souhaitez. Le code de ce tutoriel se trouve sur codesandbox. Merci.


Partager cet article

alioukahere

Mamadou Aliou Diallo

@alioukahere

Développeur web fullstack avec une passion pour l’entrepreneuriat et les nouvelles technologies. Fondateur de Kaherecode.