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>×</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>×</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>×</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.
Participe à la discussion