React est un framework de Javascript développé initialement par Facebook en 2013. Il est aujourd’hui sous licence MIT, c’est-à-dire qu’il est modifiable par la communauté.
Ce framework ne gère que la vue de l’application MVC.
Table des matières : [Masquer]
- 0.1 🖥 Prérequis
- 0.2 🖥 Extensions pour l’IDE
- 0.3 🖥 Pour installer React
- 0.4 🖥 Lancer le projet
- 0.5 🖥 Ajouter les fichiers
- 0.6 🖥 Mettre en place un système de routage
- 0.7 🖥 Créer les composants
- 0.8 🖥 Ajouter le composant aux pages
- 0.9 🖥 Modifier et importer style.css dans index.jsx
- 0.10 🖥 Créer le composant logo et l’importer dans Navbar.js
- 0.11 🖥 Installer Axios
- 0.12 🖥 Exemple Utilisation Axios
- 0.13 🖥 Mise en place d’une connexion sécurisée côté frontend
- 0.14 🖥 React-hoock-form 🔗https://react-hook-form.com/
- 0.15 🖥 React-icons 🔗https://www.npmjs.com/package/react-icons
- 0.16 🖥 installer la bibliothèque
- 0.17 🖥 Créer un dossier services dans src.
- 0.18 🖥 Dans ce dossier créer un fichier Token.jsx.
- 0.19 🖥 Créer un composant RegisterForm.jsx
- 0.20 🖥 Construire une page Register.jsx dans le dossier page.
- 0.21 🖥 Ajouter la route dans le App.jsx.
- 0.22 🖥 Créer la page login
- 0.23 🖥 Créer la page Login.jsx.
- 0.24 🖥 Ajouter la route dans App.jsx
- 0.25 🖥 Pour restreindre l’accès à certaines pages en utilisant le token.
- 1 📚 Documentation Officielle
- 2 🎓 Tutoriels et Apprentissage
- 3 🎨 Templates et Modèles :
🖥 Prérequis
- Node.js et npm installés
- Projet Laravel 11 existant et configuré.
node -v
npm -v
🔗node -v v22.13.0
npm -v 10.9.2
🖥 Extensions pour l’IDE
- 🔗Simple React snippets
- Reactjs code snippets
- Mithril Emmet
- ESLint
- Prettier
- TypeScript and JavaScript Language Features
- Tailwind CSS IntelliSense
- 🔗Voir les extensions for Visual Studio Code
Astuce : Visualisation structure du projet :
- # brew install tree // Installation sous mac
- # tree -a > project_structure.txt // generation globale
- # find . -maxdepth 2 > project_structure.txt // Pour limiter la profondeur
🖥 Pour installer React
npx create-react-app 030225_front_office_tourisme
cd 030225_front_office_tourisme
Lien : 🔗https://create-react-app.dev/
🖥 Lancer le projet
npm start
❌ L’erreur indique que le module web-vitals est manquant ou n’est pas correctement installé dans votre projet React
npm uninstall web-vitals
- ❌ Supprimer ou modifier reportWebVitals.js
- ❌ Supprimer l’appel à reportWebVitals Dans src/index.js (ou src/main.js selon le projet),
- ❌ Supprimez src/reportWebVitals.js. Supprimez toutes les références à reportWebVitals dans le projet.
// import reportWebVitals from './reportWebVitals';
// reportWebVitals();
installe react-router-dom qui va simplifier la gestion des routes et Sass qui va nous permettre de l’utiliser
npm i -s react-router-dom sass react-bootstrap bootstrap axios
🔗https://react-bootstrap.netlify.app/
Suppression des fichiers inutile
Garder les fichiers index.js et App.js
import 'bootstrap/dist/css/bootstrap.min.css';
🖥 Ajouter les fichiers
- Pages
- Dossiers “layouts – pages – compenents – styles”
🖥 Mettre en place un système de routage
- Dans le fichier App.js
- Définir les routes à l’intérieur de la balise <BrowserRouter>
- 🔗https://v5.reactrouter.com/
🖥 Créer les composants
- Exemple :
- Créer le premier composant “barre de navigation”.
- Dans le dossier « components » – src “fichier Navbar.js”.
// Importation des modules nécessaires depuis React et React Router
import React from 'react';
import { NavLink } from "react-router-dom";
// Définition du composant Navbar
const Navbar = () => {
return (
// Création d'un conteneur div avec une classe CSS pour la navigation
<div className='navigation'>
<ul>
{/* Lien de navigation vers la page d'accueil */}
<NavLink to="/" className={(nav) => (nav.isActive ? "nav-active" : "")} >
<li>Accueil</li>
</NavLink>
{/* Lien de navigation vers la page du blog */}
<NavLink to="/blog" className={(nav) => (nav.isActive ? "nav-active" : "")} >
<li>Mon blog</li>
</NavLink>
</ul>
</div>
);
};
// Exportation du composant pour pouvoir l'utiliser ailleurs dans l'application
export default Navbar;
🖥 Ajouter le composant aux pages
// Importation des modules nécessaires depuis React
import React from 'react';
import Navbar from '../components/Navbar';
// Définition du composant Home
const Home = () => {
return (
<div>
{/* Affichage du composant Navbar pour la navigation */}
<Navbar />
{/* Titre principal de la page d'accueil */}
<h1>Bienvenu sur la page d'accueil</h1>
</div>
);
};
// Exportation du composant pour pouvoir l'utiliser ailleurs dans l'application
export default Home;
🖥 Modifier et importer style.css dans index.jsx
dans le dossier styles créer un fichier style.scss
mkdir -p src/styles
touch src/styles/style.scss
Ajoutez ensuite un contenu de base pour éviter les erreurs
body { background-color: #f5f5f5; }
importer les styles dans les pages
import "./styles/style.scss";
// Importation du module React
import React from 'react';
// Définition du composant Logo
const Logo = () => {
return (
// Conteneur div avec une classe CSS pour styliser le logo
<div className="logo">
{/* Affichage de l'image du logo */}
<img src="./logo.png" alt="logo" />
</div>
);
};
// Exportation du composant pour pouvoir l'utiliser ailleurs dans l'application
export default Logo;
// Importation des modules nécessaires depuis React et React Router
import React from 'react';
import { NavLink } from "react-router-dom";
import Logo from './Logo';
// Définition du composant Navbar
const Navbar = () => {
return (
// Conteneur div avec une classe CSS pour la navigation
<div className='navigation'>
{/* Affichage du composant Logo */}
<Logo />
{/* Liste de liens de navigation */}
<ul>
{/* Lien vers la page d'accueil */}
<NavLink to="/" className={(nav) => (nav.isActive ? "nav-active" : "")} >
<li>Accueil</li>
</NavLink>
{/* Lien vers la page du blog */}
<NavLink to="/blog" className={(nav) => (nav.isActive ? "nav-active" : "")} >
<li>Mon blog</li>
</NavLink>
</ul>
</div>
);
};
// Exportation du composant pour pouvoir l'utiliser ailleurs dans l'application
export default Navbar;
🖥 Installer Axios
- Pour réaliser des requêtes GET, POST, PUT, PATCH ou DELETE pour interagir avec une API.
🖥 Exemple Utilisation Axios
// Importation des modules nécessaires depuis React et axios
import React, { useEffect, useState } from 'react';
import axios from "axios";
// Définition du composant PokemonList
const PokemonList = () => {
// Déclare une variable d'état pour stocker la liste des Pokémon
const [pokemons, setPokemons] = useState([]);
// useEffect pour réaliser la requête HTTP et récupérer les données des Pokémon
useEffect(() => {
axios
.get("https://pokeapi.co/api/v2/pokemon?limit=2000") // Requête API pour obtenir la liste des Pokémon
.then((res) => setPokemons(res.data.results)); // Mise à jour de l'état avec les résultats récupérés
}, []);
// Affichage des Pokémon récupérés sous forme de liste
return (
<div>
<ul>
{pokemons.map((pokemon, index) => (
<li key={index}> {pokemon.name} </li> // Affichage du nom de chaque Pokémon
))}
</ul>
</div>
);
};
// Exportation du composant pour pouvoir l'utiliser ailleurs dans l'application
export default PokemonList;
🖥 Mise en place d’une connexion sécurisée côté frontend
🖥 React-hoock-form 🔗https://react-hook-form.com/
npm install react-hook-form
🖥 React-icons 🔗https://www.npmjs.com/package/react-icons
npm install react-icons --save
🖥 installer la bibliothèque
npm i jwt-decode
🖥 Créer un dossier services dans src.
🖥 Dans ce dossier créer un fichier Token.jsx.
// Importation du module pour décoder les JWT
import jwtDecode from "jwt-decode";
// Fonction pour récupérer le token depuis le stockage local
function getToken() {
return localStorage.getItem('access_token');
}
// Fonction pour décoder le token s'il existe
let getDecodedToken = () => {
if (getToken()) {
return jwtDecode(localStorage.getItem('access_token'));
} else {
return false;
}
};
// Fonction pour vérifier si le token est toujours valide
let getExpiryTime = () => {
// Vérifie si le token est valide et qu'il n'a pas expiré
if (getDecodedToken() && !(getDecodedToken().exp * 1000 < Date.now())) {
return true;
} else {
return localStorage.removeItem('access_token');
}
};
// Fonction pour récupérer les rôles stockés dans le token
let getRoles = () => {
// Vérifie si le token est valide
if (getExpiryTime()) {
// Le champ "roles" est stocké en string JSON, on le parse puis le convertit en string
return JSON.parse(getDecodedToken().roles).toString();
} else {
return false;
}
};
// Fonction pour récupérer l'email stocké dans le token
let getEmail = () => {
// Vérifie si le token est valide
if (getExpiryTime()) {
return getDecodedToken().email;
} else {
return false;
}
};
// Fonction pour vérifier si l'utilisateur est connecté et a le rôle d'admin
let loggedAndAdmin = () => {
// Vérifie si le token est valide et si l'utilisateur a le rôle d'administrateur
return !!(getExpiryTime() && getRoles() === 'ROLE_ADMIN');
};
// Exportation des fonctions pour une utilisation dans d'autres fichiers
export default { getToken, getDecodedToken, getRoles, getEmail, loggedAndAdmin, getExpiryTime };
🖥 Créer un composant RegisterForm.jsx
dans un dossier auth à l’intérieur du dossier components.
// Importation des modules nécessaires
import React from "react";
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import InputGroup from "react-bootstrap/InputGroup";
import { useEffect, useState } from "react";
import { useForm, Controller } from "react-hook-form";
import { useLocation, useNavigate } from "react-router-dom";
import axios from "axios";
import { AiOutlineEye, AiTwotoneEyeInvisible } from "react-icons/ai";
// Définition du composant RegisterForm
function RegisterForm() {
// Modification du titre de la page
document.title = "Inscription au site";
let navigate = useNavigate();
let location = useLocation();
// Déclaration des méthodes et états du formulaire
const {
register,
watch,
control,
handleSubmit,
formState: { errors, isDirty, isValid },
} = useForm({ mode: "onChange" });
// États des champs du formulaire
const email = watch("email", "");
const password = watch("password", "");
const name = watch("name", "");
// États pour gérer l'affichage du mot de passe et les messages d'erreur
const [showPassword, setShowPassword] = useState(false);
const [toast, setShowToast] = useState(false);
const [toastMessage, setToastMessage] = useState({});
const [errMessage, setErrMessage] = useState("");
// Fonction déclenchée lors de la soumission du formulaire
const onSubmit = (data) => {
registerForm();
};
// Fonction pour envoyer les données d'inscription à l'API
const registerForm = async () => {
setErrMessage("");
try {
const formData = new FormData();
formData.append("email", email);
formData.append("password", password);
formData.append("name", name);
const res = await axios.post(
"http://127.0.0.1:8000/api/register/",
formData,
{
headers: { "Content-Type": "multipart/form-data" },
}
);
if (res.status === 200) {
setErrMessage("");
localStorage.setItem("access_token", res.data.token);
navigate("/", { replace: true });
} else {
setToastMessage({
message: "Une erreur est survenue",
severity: "error",
});
setShowToast(true);
}
} catch (err) {
console.log(err);
}
};
// Fonction pour afficher ou masquer le mot de passe
const handleClickShowPassword = () => {
setShowPassword((prevShowPassword) => !prevShowPassword);
};
// Affichage du formulaire
return (
<Form onSubmit={handleSubmit(onSubmit)}>
<h3 className="Auth-form-title">Créer un compte</h3>
{/* Champ pour le pseudo */}
<Form.Group className="mb-3" controlId="formBasicText">
<Form.Label>Pseudo</Form.Label>
<Form.Control
type="text"
placeholder="Votre pseudo"
{...register("name", { required: "Pseudo obligatoire" })}
/>
{errors.name && <Form.Text className="text-danger">{errors.name.message}</Form.Text>}
</Form.Group>
{/* Champ pour l'adresse mail */}
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Adresse mail</Form.Label>
<Form.Control
type="email"
placeholder="johndoe@unknown.fr"
{...register("email", { required: "Adresse mail obligatoire" })}
/>
{errors.email && <Form.Text className="text-danger">{errors.email.message}</Form.Text>}
</Form.Group>
{/* Champ pour le mot de passe */}
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Mot de passe</Form.Label>
<InputGroup>
<InputGroup.Text>
<i onClick={handleClickShowPassword}>
{showPassword ? <AiOutlineEye /> : <AiTwotoneEyeInvisible />}
</i>
</InputGroup.Text>
<Form.Control
type={showPassword ? "text" : "password"}
placeholder="Mot de passe"
{...register("password", {
required: "Mot de passe est obligatoire",
minLength: {
value: 8,
message: "Longueur minimale de 8 caractères",
},
pattern: {
value: /(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#:$%^&])/,
message:
"Le mot de passe doit contenir une minuscule, une majuscule, un chiffre et un caractère spécial",
},
})}
/>
</InputGroup>
{errors.password && <Form.Text className="text-danger">{errors.password.message}</Form.Text>}
</Form.Group>
{/* Bouton de soumission */}
<Button variant="primary" type="submit">Créer un compte</Button>
</Form>
);
}
// Exportation du composant pour une utilisation ailleurs
export default RegisterForm;
🖥 Construire une page Register.jsx dans le dossier page.
// Importation des composants nécessaires
import Players from "./pages/players/Players";
import AddPlayer from "./pages/players/AddPlayer";
import EditPlayer from "./pages/players/EditPlayer";
import Home from "./pages/Home";
import Register from "./pages/Register";
// Définition du composant principal de l'application
function App() {
return (
// Utilisation de BrowserRouter pour la gestion des routes
<BrowserRouter>
<Routes>
{/* Route vers la page d'accueil */}
<Route path="/" element={<Home />} />
{/* Route vers la page d'inscription */}
<Route path="/register" element={<Register />} />
{/* Routes pour la gestion des clubs */}
<Route path="/clubs" element={<Clubs />} />
<Route path="/clubs/add" element={<AddClub />} />
<Route path="/clubs/edit/:club" element={<EditClub />} />
{/* Routes pour la gestion des joueurs */}
<Route path="/players" element={<Players />} />
<Route path="/players/add" element={<AddPlayer />} />
<Route path="/players/edit/:player" element={<EditPlayer />} />
{/* Route de secours pour toute URL inconnue, redirige vers la page d'accueil */}
<Route path="*" element={<Home />} />
</Routes>
</BrowserRouter>
);
}
// Exportation du composant principal
export default App;
🖥 Ajouter la route dans le App.jsx.
<Route path="/register" element={<Register />} />
🖥 Créer la page login
Composant LoginForm.jsx dans le même dossier que RegisterForm.jsx.
// Importation des modules nécessaires
import Button from "react-bootstrap/Button";
import Form from "react-bootstrap/Form";
import InputGroup from "react-bootstrap/InputGroup";
import { useEffect, useRef, useState } from "react";
import { useForm, Controller } from "react-hook-form";
import { useLocation, useNavigate } from "react-router-dom";
import axios from "axios";
import { AiOutlineEye, AiTwotoneEyeInvisible } from "react-icons/ai";
// Définition du composant LoginForm
function LoginForm() {
// Modification du titre de la page
document.title = "Connexion au site";
// Déclaration des états du formulaire
const [errMessage, setErrMessage] = useState("");
const [showPassword, setShowPassword] = useState(false);
const [toast, setShowToast] = useState(false);
const [toastMessage, setToastMessage] = useState({});
// Utilisation de useForm pour gérer le formulaire
const {
register,
control,
handleSubmit,
watch,
formState: { errors },
} = useForm({ defaultValues: { email: "", password: "" } });
// Récupération des valeurs des champs
const email = watch("email", "");
const password = watch("password", "");
// Gestion de la navigation et de la redirection après connexion
let navigate = useNavigate();
let location = useLocation();
let from = location.pathname || "/";
// Fonction pour gérer la connexion de l'utilisateur
let login = async () => {
try {
let formData = new FormData();
formData.append("email", email);
formData.append("password", password);
let res = await axios.post("http://127.0.0.1:8000/api/login/", formData, {
headers: { "Content-Type": "multipart/form-data" },
});
if (res.status === 200) {
localStorage.setItem("access_token", res.data.data.access_token.token);
navigate("/home", { replace: true });
}
} catch (err) {}
};
// Fonction pour afficher ou masquer le mot de passe
const handleClickShowPassword = () => {
setShowPassword((prev) => !prev);
};
// Affichage du formulaire de connexion
return (
<Form onSubmit={handleSubmit(login)}>
<h3 className="Auth-form-title">Connexion</h3>
{/* Champ pour l'adresse mail */}
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Adresse mail</Form.Label>
<Form.Control
type="email"
placeholder="johndoe@unknown.fr"
{...register("email", { required: "Mail obligatoire" })}
/>
{errors.email && <Form.Text className="text-danger">{errors.email.message}</Form.Text>}
</Form.Group>
{/* Champ pour le mot de passe */}
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Mot de passe</Form.Label>
<InputGroup>
<InputGroup.Text>
<i onClick={handleClickShowPassword}>
{showPassword ? <AiOutlineEye /> : <AiTwotoneEyeInvisible />}
</i>
</InputGroup.Text>
<Form.Control
type={showPassword ? "text" : "password"}
placeholder="Mot de passe"
{...register("password", { required: "Mot de passe est obligatoire" })}
/>
</InputGroup>
{errors.password && <Form.Text className="text-danger">{errors.password.message}</Form.Text>}
</Form.Group>
{/* Bouton de soumission */}
<Button variant="primary" type="submit">
Se connecter
</Button>
{/* Lien vers la récupération de mot de passe */}
<p className="forgot-password text-right mt-2">
Mot de passe <a href="#">oublié?</a>
</p>
</Form>
);
}
// Exportation du composant pour une utilisation ailleurs
export default LoginForm;
🖥 Créer la page Login.jsx.
// Importation des modules nécessaires
import Container from "react-bootstrap/Container";
import LoginForm from "../components/Auth/LoginForm";
import Menu from "../components/Menu";
// Définition du composant Login
function Login() {
return (
<div>
{/* Affichage du menu de navigation */}
<Menu />
{/* Conteneur principal de la page de connexion */}
<Container fluid className="loginContainer">
{/* Affichage du formulaire de connexion */}
<LoginForm />
</Container>
</div>
);
}
// Exportation du composant pour une utilisation ailleurs
export default Login;
🖥 Ajouter la route dans App.jsx
Pour pouvoir envoyer un token dans la requête d’API, il faut le récupérer.
const token = localStorage.getItem("access_token");
// Fonction pour récupérer et afficher la liste des clubs
const displayClubs = async () => {
await axios.get("http://127.0.0.1:8000/api/clubs", {
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${token}`, // Utilisation du token pour l'authentification
},
}).then((res) => {
setClubs(res.data); // Mise à jour de l'état avec les données récupérées
});
};
// Fonction pour supprimer un club spécifique
const deleteClub = (id) => {
axios.delete(`http://127.0.0.1:8000/api/clubs/${id}`, {
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${token}`, // Authentification requise pour la suppression
},
}).then(displayClubs); // Rafraîchissement de la liste après suppression
};
🖥 Pour restreindre l’accès à certaines pages en utilisant le token.
il suffit de mettre en place une condition de ce type :
<Route path="/xxxxx" element={token ? <xxxxx/> : <Login/> }></Route>
📚 Documentation Officielle
- React.js Official Documentation : La documentation officielle de React est la meilleure ressource pour comprendre les nouvelles fonctionnalités et API de React 19.
🔗 https://react.dev
🎓 Tutoriels et Apprentissage
- Kinsta – 15+ Tutoriels sur React : Une compilation des meilleurs tutoriels et ressources pour apprendre React.
🔗 https://kinsta.com/blog/best-react-tutorials/ - FreeCodeCamp – Guide Complet React : Un excellent guide détaillé pour apprendre React depuis les bases jusqu’aux concepts avancés.
🔗 https://www.freecodecamp.org/news/the-react-handbook-b71c27b0a795/
🎨 Templates et Modèles :
- ThemeForest – Templates React : Une large collection de thèmes React premium pour différents types de projets.
🔗 https://themeforest.net/category/site-templates/react-templates - Creative Tim – UI Kits & Templates : Des kits d’interface utilisateur et des dashboards basés sur React pour un développement rapide.
🔗 https://www.creative-tim.com/templates/react - Github – Awesome React : Une liste collaborative des meilleures ressources pour React, incluant des templates et outils utiles.
🔗 https://github.com/enaqx/awesome-react