Hey salut, bienvenue dans ce tutoriel sur React. Nous allons ensemble créer un composant React pour afficher un module d'onglets sur nos pages web. Tu peux déjà voir la version finale de ce que nous allons créer sur ce CodeSandbox.
Les onglets vont nous permettre d'afficher différents contenus sur une page web et permettre à nos utilisateurs de naviguer entre ce contenu en cliquant sur des onglets.
Nous allons dans notre cas créer deux composants:
Tab
qui va afficher le contenu d'un ongletTabs
qui va afficher une liste de composantTab
cliquable, maintenir l'état (state
) pour savoir quel onglet est actif
Je vais dans ce tutoriel utiliser CodeSandbox pour ne pas avoir à installer un nouveau projet React sur mon ordinateur. Je vais créer un fichier tabs.js
dans lequel je définirai les deux composants Tab
et Tabs
, et ensuite importer ces composants dans le composant App
. Je vais commencer par créer le composant Tab
, qui doit afficher un seul onglet avec son contenu. C'est parti.
// tabs.js
import React from "react";
import PropTypes from "prop-types";
export const Tab = ({ title }) => (
<li className="tab-item">{title}</li>
);
Tab.propTypes = {
title: PropTypes.string.isRequired
};
C'est tout pour l'instant, notre composant va juste prendre un paramètre title
et retourner un élément HTML <li>
avec le paramètre title
.
Nous allons maintenant créer le composant Tabs
, toujours dans le même fichier:
// tabs.js
import React from "react";
import PropTypes from "prop-types";
export const Tab = ({ title }) => (
<li className="tab-item">{title}</li>
);
export default function Tabs() {
return (
<div className="tabs">
<ul className="tab-list">
{/* Render a list of Tab component */}
</ul>
<div className="tab-content">
{/* Render the content of a Tab if it's active */}
</div>
</div>
);
}
Tab.propTypes = {
title: PropTypes.string.isRequired
};
La structure du composant Tabs
est plutôt simple aussi, nous affichons une liste de composant Tab
dans un élément HTML <ul>
, puis le contenu de l'onglet actif dans la balise <div>
juste en dessous, nous allons tout de suite voir comment mettre tout cela en pratique, mais avant, nous allons importer nos composants dans le composant App
et créer un module à onglet:
// App.js
import React from "react";
import Tabs from "./Tabs";
export default function App() {
return (
<>
<h1>Hello I'm Aliou Diallo!</h1>
<Tabs>
<div title="about">
<h3>About me</h3>
<p>
I'm Mamadou Aliou Diallo a.k.a alioukahere. A Web Developer (Python,
PHP, JS, ...Web), Technical Writer, Passionate about
entrepreneurship, writing and teaching code. Currently working on
Kaherecode (<a href="https://www.kaherecode.com">kaherecode.com</a>
), an aspiring community for french developers, a web platform to
learn and share about programming.
</p>
</div>
<div title="experiences">
<h3>My experiences</h3>
<ul>
<li>
<strong>Web Full Stack Developer - Kewel (2019 - Present)</strong>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
porta, libero nec maximus varius, sapien lorem aliquet ex, quis
faucibus odio lorem in quam.
</p>
</li>
<li>
<strong>
Web Full Stack Developer - Qualshore (2017 - 2019)
</strong>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
porta, libero nec maximus varius, sapien lorem aliquet ex, quis
faucibus odio lorem in quam.
</p>
</li>
</ul>
</div>
<div title="contact">
<h3>Get in touch</h3>
<p>
<strong>Mail</strong>:{" "}
<a href="mailto:aliou.diallo@kaherecode.com">
aliou.diallo@kaherecode.com
</a>{" "}
<br />
<strong>Adress</strong>:Dakar, Senegal
</p>
</div>
</Tabs>
</>
);
}
Et voilà, le composant Tabs
contient 3 autres blocs div
qui sont les différents onglets et leur contenu.
Pour l'instant, rien n'est afficher sur la page à part l'élément h1
. Nous allons commencer par afficher juste les onglets, sans le contenu. Dans le fichier tabs.js
:
// tabs.js
import React from "react";
import PropTypes from "prop-types";
export const Tab = ({ title }) => <li className="tab-item">{title}</li>;
export default function Tabs({ children }) {
return (
<div className="tabs">
<ul className="tab-list">
{children.map(tab => {
const { title } = tab.props;
return <Tab key={title} title={title} />;
})}
</ul>
<div className="tab-content">
{/* Render the content of a Tab if it's active */}
</div>
</div>
);
}
Tab.propTypes = {
title: PropTypes.string.isRequired
};
Tabs.propTypes = {
children: PropTypes.instanceOf(Array).isRequired
};
Je modifie le composant Tabs
pour parcourir le tableau children
et à chaque fois je retourne un nouveau composant Tab
.
Nous avons maintenant un début de notre composant d'onglets qui s'affiche comme sur l'image suivante:
Nous allons juste apporter un peu de CSS, je vais utiliser styled-jsx pour celà:
// tabs.js
import React from "react";
import PropTypes from "prop-types";
export const Tab = ({ title }) => (
<>
<li className="tab-item">{title}</li>
<style jsx="true">{`
li.tab-item {
list-style-type: none;
padding: 1rem 2rem;
background-color: #b2beb5;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.1rem;
cursor: pointer;
transition: all 0.5s ease;
}
li.tab-item:hover {
background-color: #76fa97;
}
`}</style>
</>
);
export default function Tabs({ children }) {
return (
<>
<div className="tabs">
<ul className="tab-list">
{children.map(tab => {
const { title } = tab.props;
return <Tab key={title} title={title} />;
})}
</ul>
<div className="tab-content">
{/* Render the content of a Tab if it's active */}
</div>
</div>
<style jsx="true">{`
.tab-list {
padding: 0;
display: flex;
}
`}</style>
</>
);
}
Tab.propTypes = {
title: PropTypes.string.isRequired
};
Tabs.propTypes = {
children: PropTypes.instanceOf(Array).isRequired
};
Notre composant commence à prendre forme.
Mais on est encore loin du compte, il nous faut maintenant afficher le contenu de nos onglets, nous allons aussi utiliser la fonction map
de javascript pour parcourir le tableau children
du composant Tabs
et afficher le contenu de chaque élément:
// tabs.js
import React from "react";
import PropTypes from "prop-types";
export const Tab = ({ title }) => (
<>
<li className="tab-item">{title}</li>
<style jsx="true">{`
li.tab-item {
list-style-type: none;
padding: 1rem 2rem;
background-color: #b2beb5;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.1rem;
cursor: pointer;
transition: all 0.5s ease;
}
li.tab-item:hover {
background-color: #76fa97;
}
`}</style>
</>
);
export default function Tabs({ children }) {
return (
<>
<div className="tabs">
<ul className="tab-list">
{children.map(tab => {
const { title } = tab.props;
return <Tab key={title} title={title} />;
})}
</ul>
<div className="tab-content">
{/* Render the content of a Tab if it's active */}
{children.map(tab => tab.props.children)}
</div>
</div>
<style jsx="true">{`
.tab-list {
padding: 0;
display: flex;
}
`}</style>
</>
);
}
Tab.propTypes = {
title: PropTypes.string.isRequired
};
Tabs.propTypes = {
children: PropTypes.instanceOf(Array).isRequired
};
J'ai juste rajouter la ligne {children.map(tab => tab.props.children)}
qui va parcourir tous les enfants du composant Tabs
puis afficher leurs enfants à eux (complex tout ça), et nous avons quelque chose comme cela:
Ce n'est pas ce que nous voulons.
Si tu lis le commentaire juste avant, il est dit qu'il faut afficher le contenu de l'onglet qui est actif, mais pour l'instant nous ne pouvons pas savoir quel onglet est actif.
Tu te rappelles, au début on disait que le composant Tabs
devrait servir a afficher la liste de composant Tab
, mais aussi à maintenir l'état pour savoir quel onglet est actif. Nous allons donc utiliser useState de React pour créer un état activeTab
. Cet état contiendra le title
de l'onglet qui est actif. Nous allons par défaut l'initialiser avec le premier onglet, et ensuite nous afficherons le contenu d'un onglet que si son title
équivaut au state activeTab
:
// tabs.js
import React, { useState } from "react";
import PropTypes from "prop-types";
export const Tab = ({ title }) => (
<>
<li className="tab-item">{title}</li>
<style jsx="true">{`
li.tab-item {
list-style-type: none;
padding: 1rem 2rem;
background-color: #b2beb5;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.1rem;
cursor: pointer;
transition: all 0.5s ease;
}
li.tab-item:hover {
background-color: #76fa97;
}
`}</style>
</>
);
export default function Tabs({ children }) {
const [activeTab, setActiveTab] = useState(children[0].props.title);
return (
<>
<div className="tabs">
<ul className="tab-list">
{children.map(tab => {
const { title } = tab.props;
return <Tab key={title} title={title} />;
})}
</ul>
<div className="tab-content">
{children.map(tab => {
if (tab.props.title !== activeTab) return undefined;
return tab.props.children;
})}
</div>
</div>
<style jsx="true">{`
.tab-list {
padding: 0;
display: flex;
}
.tab-content {
padding: 0 1rem;
}
.tab-content p {
text-align: justify;
}
`}</style>
</>
);
}
Tab.propTypes = {
title: PropTypes.string.isRequired
};
Tabs.propTypes = {
children: PropTypes.instanceOf(Array).isRequired
};
Et boom, nous avons juste le contenu de l'onglet About
qui est afficher.
Mais nous ne pouvons pas changer d'onglet pour l'instant.
Pour remedier à cela, nous allons créer une méthode onClickTabItem
qui va modifier le state activeTab
du composant, puis nous enverrons cette méthode à notre composant Tab
qui va écouter l'évènement onClick
:
// tabs.js
import React, { useState } from "react";
import PropTypes from "prop-types";
export const Tab = ({ title, onClick, active = false }) => {
const onClickTab = e => {
e.preventDefault(0);
onClick(title);
};
return (
<>
<li className={`${active ? "active" : ""} tab-item`} onClick={onClickTab}>
{title}
</li>
<style jsx="true">{`
li.tab-item {
list-style-type: none;
padding: 1rem 2rem;
background-color: #b2beb5;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.1rem;
cursor: pointer;
transition: all 0.5s ease;
}
li.tab-item:hover,
li.tab-item.active {
background-color: #76fa97;
}
`}</style>
</>
);
};
export default function Tabs({ children }) {
const [activeTab, setActiveTab] = useState(children[0].props.title);
const onClickTabItem = tab => setActiveTab(tab);
return (
<>
<div className="tabs">
<ul className="tab-list">
{children.map(tab => {
const { title } = tab.props;
return (
<Tab
key={title}
title={title}
onClick={onClickTabItem}
active={title === activeTab ? true : false}
/>
);
})}
</ul>
<div className="tab-content">
{children.map(tab => {
if (tab.props.title !== activeTab) return undefined;
return tab.props.children;
})}
</div>
</div>
<style jsx="true">{`
.tab-list {
padding: 0;
display: flex;
}
.tab-content {
padding: 0 1rem;
}
.tab-content p {
text-align: justify;
}
`}</style>
</>
);
}
Tab.propTypes = {
title: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired
};
Tabs.propTypes = {
children: PropTypes.instanceOf(Array).isRequired
};
Et voilà, notre composant d'onglets est maintenant fonctionnel, tu peux changer d'onglets comme tu le souhaites et nous avons même un statut actif ou pas pour changer la couleur de fond de l'onglet actif.
Si tu veux utiliser ce composant, tu prends juste le contenu du fichier tabs.js
, tu modifies le style CSS à tes besoins et tu mets le contenu de tes onglets dans un composant Tabs
comme nous l'avons fait dans le fichier App.js
. Le code source est disponible sur ce CodeSandbox.
Merci d'avoir suivi ce tutoriel, si tu as des questions ou remarques n'hésite pas à laisser un commentaire ci-dessous ou à me joindre sur le chat Discord de Kaherecode ou je serais plus apte à te répondre le plus vite possible.
Participe à la discussion