Skip to content

WildCodeSchool-2024-09/JS-RemoteFR-Blue-Recap

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 

Repository files navigation

Formation DWWM - 2024 | Team Blue

Notes de cours, exercices et projets réalisés dans le cadre de la formation Développeur Web et Web Mobile.

Lien utile
Cours
Exercices
Recap des présentations

Sommaire

  • Saison 1
    • HTML / CSS / JavaScript (La trinité du web 💪)
  • Saison 2
    • React / Props / State / Hooks
  • Saison 3
    • Méthode agile / Workflows git / Context
  • Saison 4
    • API / Fetch / Express / MySQL / Merise
  • Saison 5
    • Middleware / Authentification / Tests / JWT / Argon2
  • Saison Bonus
    • Plein de livecoding ❤️

Au revoir la team ! 🚀

Woaw, passer 5 mois avec vous a été une expérience incroyable, j'ai appris énormément de choses et j'ai adoré partager mes connaissances avec vous ! N'oubliez pas que vous êtes des développeurs incroyables et que vous avez tout ce qu'il faut pour réussir dans ce domaine. Continuez à apprendre, à coder et à vous amuser, et surtout, n'oubliez pas de prendre soin de vous et de vous reposer (prenez des pauses !) Je vous souhaite à tous une belle continuation dans vos projets et j'espère vous revoir bientôt avec d'excellentes nouvelles ! 🚀

bye

Saison Bonus

📆 03/02/2025

📦 Récap du jour

Nous allons voir comment créer des routes protégées avec React.

Les routes protégées

Pour protéger une route, nous allons utiliser un HOC (Higher Order Component).

// ./src/components/ProtectedRoute.tsx
import { Navigate, Outlet } from "react-router-dom";
import { useAuth } from "../context/AuthContext";

function ProtectedRoute() {
	const { isAuthenticated } = useAuth();
	return isAuthenticated ? <Outlet /> : <Navigate to={redirectTo} />;
}

export default ProtectedRoute;

Et voilà !

Maintenant, pour protéger une route, il suffit de l'entourer avec notre ProtectedRoute.

// ./src/main.tsx
const router = createBrowserRouter([
	{
		element: <Layout />,
		children: [
			{
				path: "/",
				element: <App />,
			},
			{
				path: "/login",
				element: <Login />,
			},
			{
				path: "/signin",
				element: <SignIn />,
			},
			// Routes protégées pour les utilisateurs connectés
			{
				element: <ProtectedRoute />,
				children: [
					{
						path: "/profile",
						element: <Profile />, // Page profil
					},
					{
						path: "/cart",
						element: <Cart />, // Page panier
					},
				],
			},
		],
	},
]);

🔗 Liens utiles


📆 28/01/2025

📦 Récap du jour

Nous allons faire un petit livecoding pour le fameux forgot password. Nous allons mettre en place plein de petites choses, alors, oui, ça peut être un peu difficile, mais en vrai c'est cool !

Mise à jour de notre schema

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Création d'un table pour stocker les tokens
CREATE TABLE password_resets (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    token VARCHAR(64) NOT NULL,
    expires_at DATETIME NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

Création d'un token dans notre server

/**
 * Ici, je met tout sur une seule page sans prendre le temps de ranger dans des dossiers.
 * Il faudra bien sûr ranger tout ça dans des fichiers séparés en l'adaptant à votre architecture.
 */
import express from "express";
import crypto from "node:crypto";
import nodemailer from "nodemailer";
import pool from "../db.js";

const router = express.Router();

// 📌 1️⃣ Route pour demander la réinitialisation du mot de passe
router.post("/forgot-password", async (req, res) => {
	const { email } = req.body;

	try {
		const [users] = await pool.query(
			"SELECT id FROM users WHERE email = ?",
			[email]
		);

		if (users.length === 0) {
			return res.status(400).json({ message: "Email non trouvé" });
		}

		const userId = users[0].id;

		// Génère un token sécurisé
		const resetToken = crypto.randomBytes(32).toString("hex");
		const hashedToken = crypto
			.createHash("sha256")
			.update(resetToken)
			.digest("hex");
		const expiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 min

		// Supprimer les anciens tokens
		await pool.query("DELETE FROM password_resets WHERE user_id = ?", [
			userId,
		]);

		// Sauvegarde le token en base de données
		await pool.query(
			"INSERT INTO password_resets (user_id, token, expires_at) VALUES (?, ?, ?)",
			[userId, hashedToken, expiresAt]
		);

		// Envoi de l'email avec le lien
		const resetLink = `http://localhost:3000/reset-password?token=${resetToken}&email=${email}`;

		await transporter.sendMail({
			to: email,
			subject: "Réinitialisation de votre mot de passe",
			text: `Cliquez sur ce lien pour réinitialiser votre mot de passe : ${resetLink}`,
		});

		res.json({ message: "Email envoyé ! Vérifiez votre boîte mail." });
	} catch (error) {
		console.error(error);
		res.status(500).json({ message: "Erreur serveur" });
	}
});

// 📌 2️⃣ Route pour réinitialiser le mot de passe
router.post("/reset-password", async (req, res) => {
	const { token, email, newPassword } = req.body;

	try {
		const [users] = await pool.query(
			"SELECT id FROM users WHERE email = ?",
			[email]
		);

		if (users.length === 0) {
			return res.status(400).json({ message: "Email invalide" });
		}

		const userId = users[0].id;
		const hashedToken = crypto
			.createHash("sha256")
			.update(token)
			.digest("hex");

		// Vérifier le token en base
		const [tokens] = await pool.query(
			"SELECT * FROM password_resets WHERE user_id = ? AND token = ? AND expires_at > NOW()",
			[userId, hashedToken]
		);

		if (tokens.length === 0) {
			return res
				.status(400)
				.json({ message: "Token invalide ou expiré" });
		}

		// Hacher le nouveau mot de passe avec Argon2
		const hashedPassword = await argon2.hash(newPassword);

		// Mettre à jour le mot de passe
		await pool.query("UPDATE users SET password = ? WHERE id = ?", [
			hashedPassword,
			userId,
		]);

		// Supprimer le token après utilisation
		await pool.query("DELETE FROM password_resets WHERE user_id = ?", [
			userId,
		]);

		res.json({ message: "Mot de passe mis à jour avec succès" });
	} catch (error) {
		console.error(error);
		res.status(500).json({ message: "Erreur serveur" });
	}
});

export default router;

Création des pages React

// ./src/pages/ForgotPassword.tsx
import { useState } from "react";
import axios from "axios";

const ForgotPassword = () => {
	const [email, setEmail] = useState("");

	const handleSubmit = async (e) => {
		e.preventDefault();
		await axios.post("http://localhost:3310/api/forgot-password", {
			email,
		});
		alert("Si l'email existe, un lien a été envoyé.");
	};

	return (
		<form onSubmit={handleSubmit}>
			<input
				type="email"
				placeholder="Email"
				onChange={(e) => setEmail(e.target.value)}
				required
			/>
			<button type="submit">Envoyer</button>
		</form>
	);
};

export default ForgotPassword;

Une fois que le formulaire remplie, vous arrivez sur la page reset-password grâce au lien envoyé par email.

// ./src/pages/ResetPassword.tsx
import { useState } from "react";
import { useSearchParams } from "react-router-dom";
import axios from "axios";

const ResetPassword = () => {
	const [searchParams] = useSearchParams();
	const email = searchParams.get("email");
	const token = searchParams.get("token");

	const [password, setPassword] = useState("");

	const handleSubmit = async (e) => {
		e.preventDefault();
		await axios.post("http://localhost:3310/api/reset-password", {
			email,
			token,
			newPassword: password,
		});
		alert("Mot de passe réinitialisé !");
	};

	return (
		<form onSubmit={handleSubmit}>
			<input
				type="password"
				placeholder="Nouveau mot de passe"
				onChange={(e) => setPassword(e.target.value)}
				required
			/>
			<button type="submit">Changer</button>
		</form>
	);
};

export default ResetPassword;

Et voilà ! Vous avez un système de réinitialisation de mot de passe.

🔗 Liens utiles


📆 24/01/2025

📦 Récap du jour

Nous allons voir comment fonctionne l'envoi de mail avec Node.js.

Nodemailer

Installation
npm install nodemailer
Utilisation
// ./src/helpers/transporter.ts
import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
	host: "smtp.ethereal.email",
	port: 587,
	auth: {
		user: process.env.MAIL_USER,
		pass: process.env.MAIL_PASS,
	},
});

export { transporter };
// ./src/helpers/sendMail.ts
import { transporter } from "./transporter";

const sendMail = async (to: string, subject: string, text: string) => {
	const info = await transporter.sendMail({
		from: "noreply@gmail.com",
		to,
		subject,
		text,
	});

	console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
};

export { sendMail };

Je vous invite à voir le repository pour voir aussi comment envoyer un template HTML avec EJS & Nodemailer.

🔗 Liens utiles


📆 22/01/2025

📦 Récap du jour

Des petits tips en vetu en voilà !

Axios

Et oui, nous utilisons axios pour faire des requêtes HTTP, c'est très bien, mais marquer tout le temps

const response = await axios.get("http://localhost:3310");
const response = await axios.post("http://localhost:3310", data);
const restponse = await axios.put("http://localhost:3310", data);
// etc...

C'est un peu répétitif, non ?

Surtout que si je met en ligne mon site, je vais devoir changer toutes les URL. plusieurs fois. 😱

Et bien, il existe une solution, une solution simple, une solution élégante, une solution qui va vous changer la vie !

// ./src/helpers/api.ts
import axios from "axios";

const api = axios.create({
	baseURL: import.meta.env.VITE_API_URL ?? "http://localhost:3310",
});

export { api };

Grâce à axios.create, je crée une instance d'axios avec une URL de base.

Et maintenant, je peux faire des requêtes HTTP de cette manière :

// ./src/components/MyComponent.tsx
import { api } from "../helpers/api";

const MyComponent = () => {
	const fetchData = async () => {
		const response = await api.get("/users");
		console.log(response.data);
	};

	return (
		<div>
			<button onClick={fetchData}>Fetch data</button>
		</div>
	);
};

export default MyComponent;

Je n'importe plus axios, et je n'ai plus besoin de mettre l'URL de base à chaque fois.

Nous avons aussi, pour allez plus loin, la possibilité de créer des interceptors, n'hésitez pas à regarder la documentation.

AuthContext

Nous avons vu comment créer un AuthContext pour gérer l'authentification.

// ./src/context/AuthContext.tsx
import { createContext, useContext, useState } from "react";

type AuthContextType = {
	user: User | null;
	handleLogin: (user: User) => void;
	handleLogout: () => void;
};

const AuthContext = createContext<AuthContextType | null>(null);

type ChildrenType = {
	children: React.ReactNode;
};

type User = {
	id: number;
	email: string;
	avatar: string;
};

export function AuthProvider({ children }: ChildrenType) {
	const [user, setUser] = useState<User | null>(null);

	// handleLogin permet d'enregistrer l'utilisateur connecté dans le context
	const handleLogin = (user: User) => {
		setUser(user);
	};

	// handleLogout permet de déconnecter l'utilisateur coté client, mais il ne faut pas oublier de le déconnecter coté serveur avec une requête HTTP par exemple.
	const handleLogout = () => {
		setUser(null);
	};

	return (
		<AuthContext.Provider
			value={{
				user,
				handleLogin,
				handleLogout,
			}}
		>
			{children}
		</AuthContext.Provider>
	);
}

// useAuth est un Custom Hook qui permet de récupérer le context
export const useAuth = () => {
	const value = useContext(AuthContext);

	if (value == null) {
		throw new Error("useAuth has to be used within <AuthProvider />");
	}

	return value;
};

🔗 Liens utiles


📆 21/01/2025

📦 Récap du jour

Installation et utilisation d'un JWT (JSON Web Token) pour l'authentification.

JWT

Un JSON Web Token (JWT) est un standard ouvert (RFC 7519) qui définit une manière compacte et autonome de transmettre des informations entre les parties en tant qu'objet JSON.

Un JWT se compose de trois parties :

  • Header
  • Payload
  • Signature

Installation

npm install jsonwebtoken

Utilisation

// ./src/middleware/jwtMiddleware.ts
import { Request, Response, NextFunction } from "express";
import jwt from "jsonwebtoken";

const createToken = (user: User) => {
	return jwt.sign({ user }, process.env.JWT_SECRET, {
		expiresIn: "1h",
	});
};

const verifyToken = (req: Request, res: Response, next: NextFunction) => {
	const token = req.cookies.token;

	if (!token) {
		res.status(401).json({ message: "Unauthorized" });
		return;
	}

	try {
		const user = jwt.verify(token, process.env.JWT_SECRET);
		req.user = user;
		next();
	} catch (error) {
		res.status(401).json({ message: "Unauthorized" });
	}
};

export { createToken, verifyToken };

Et maintenant, nous allons l'utiliser dans notre server.

// ./src/actions/auth.ts

import { Request, Response } from "express";
import { authRepository } from "../repositories/auth";

import { createToken } from "../services/jwt";

const login = async (req: Request, res: Response) => {
	const { email, password } = req.body;

	const user = await authRepository.findOne({ email, password });

	if (!user) {
		res.status(401).json({ message: "Invalid credentials" });
		return;
	}

	// Ici, nous créons un token JWT
	const token = createToken(user);

	// Et nous le passons dans un cookie (ne pas oublier d'installer cookie-parser)
	res.cookie("token", token, { httpOnly: true }).json({
		message: "Logged in",
	});
};

export { login };

Et avec le verifyToken nous pouvons avoir des routes sécurisées.

Utilisation dans une route

// ./src/routes/users.ts
import { Router } from "express";

import { verifyToken } from "../middlewares/jwtMiddleware";

const router = Router();

router.get("/users", verifyToken, (req, res) => {
	res.json({ message: "Users" });
});

export { router };

🔗 Liens utiles


📆 17/01/2025

📦 Récap du jour

Nous continuons avec les livecoding sur des cas précis, ici, nous allons parler de l'upload de fichier.

Upload de fichier

Nous allons voir comment uploader un fichier sur notre serveur.

Voilà un exemple de code pour uploader un fichier avec Express.

// ./src/routes/upload.ts
import { Router } from "express";

const router = Router();

router.post("/upload", (req, res) => {
	res.json({ message: "File uploaded" });
});

export { router };

Nous allons créer un middleware pour gérer l'upload de fichier. Tout d'abord, nous allons installer multer.

npm install multer

Ensuite, nous allons créer un fichier uploadMiddleware.ts dans notre dossier middlewares.

// ./src/middlewares/uploadMiddleware.ts
import { Request, Response, NextFunction } from "express";
import multer from "multer";

// configuration de multer
const storage = multer.diskStorage({
	// La destination du fichier, ici, dans un dossier uploads
	destination: function (req, file, cb) {
		cb(null, "uploads/");
	},
	// Le nom du fichier, ici, on garde le nom original, mais on peut le renommer
	/**
	 * exemple :
	 * filename: (req, file, cb) => {
			const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
			req.body.filename = uniqueSuffix + path.extname(file.originalname);
			cb(null, uniqueSuffix + path.extname(file.originalname));
		}
	 * 
	 * */
	filename: function (req, file, cb) {
		req.body.filename = file.originalname;
		cb(null, file.originalname);
	},
});

const upload = multer({ storage: storage });

const uploadMiddleware = (req: Request, res: Response, next: NextFunction) => {
	if (!req.file) {
		res.status(400).json({ message: "No file uploaded" });
		return;
	}

	next();
};

export { uploadMiddleware, upload };

Et pour finir, nous allons ajouter nos middlewares sur notre route /upload.

// ./src/routes/upload.ts
import { Router } from "express";
import { uploadMiddleware, upload } from "../middlewares/uploadMiddleware";

const router = Router();

router.post("/upload", upload.single("file"), uploadMiddleware, (req, res) => {
	res.json({ message: "File uploaded" });
});

export { router };

Nous devons envoyer notre fichier depuis react maintenant.

// ./src/components/Upload.tsx
import { useState } from "react";
import axios from "axios";

const Upload = () => {
	const [file, setFile] = useState<File | null>(null);

	const handleChange = (e) => {
		setFile(e.target.files[0]);
	};

	const handleSubmit = async () => {
		// Ici, nous allons créer un objet FormData
		// FormData est obligatoire pour envoyer un fichier et/ou des données textuelles
		const formData = new FormData();
		formData.append("file", file);

		/**
		 * Axios gere automatiquement le header Content-Type: multipart/form-data
		 * Mais dans le doute, on peut l'ajouter aussi :)
		 * 
		 * Exemple : 
		 * 
		 * const response = await axios.post(
			"http://localhost:3310/upload",
			formData,
			{
				headers: {
					"Content-Type": "multipart/form-data",
				},
			}
		);
		 * 
		 * 
		 * */

		const response = await axios.post(
			"http://localhost:3310/upload",
			formData
		);

		console.log(response.data);
	};

	return (
		<div>
			<input type="file" onChange={handleChange} />
			<button onClick={handleSubmit}>Upload</button>
		</div>
	);
};

export default Upload;

🔗 Liens utiles


📆 15/01/2025

📦 Récap du jour

On commence les livecoding sur des cas précis, ici, nous allons comprendre comment utiliser les middlewares pour sécuriser nos routes.

Register & Login

Nous allons faire des routes pour s'inscrire et se connecter.

Nous n'allons pas faire les actions, c'est juste là à titre d'exemple.

// ./src/routes/auth.ts
import { Router } from "express";

import { authAction } from "../actions/auth";

const router = Router();

router.post("/register", authAction.register);
router.post("/login", authAction.login);

AuthMiddleware

Nous allons ajouter sur nos routes ci-dessus, nos middlewares vont pouvoir hasher le mot de passe avant de l'envoyer en base de données & vérifier si l'utilisateur existe déjà.

Il ne faut pas oublier d'installer argon2.

npm install argon2
// ./src/middlewares/authMiddleware.ts

import { Request, Response, NextFunction } from "express";
import { authRepository } from "../repositories/auth";

// import de argon2 pour hasher le mot de passe
import * as argon2 from "argon2";

// function pour hasher le mot de passe
const hashPassword = async (password: string): Promise<string> => {
	return argon2.hash(password);
};

// function pour comparer le mot de passe
const comparePassword = async (
	password: string,
	hash: string
): Promise<boolean> => {
	return argon2.verify(hash, password);
};

// middleware pour vérifier si l'utilisateur existe déjà
const authMiddleware = async (
	req: Request,
	res: Response,
	next: NextFunction
) => {
	const { email, password } = req.body;

	try {
		const user = await authRepository.findOne({ email });
		if (!user) {
			res.status(401).json({ message: "User not found" });
			return;
		}

		const isPasswordValid = await comparePassword(password, user.password);
		if (!isPasswordValid) {
			res.status(401).json({ message: "Invalid password" });
			return;
		}

		req.user = user;
		next();
	} catch (error) {
		console.error(error);
		res.status(500).json({ message: "Internal server error" });
	}
};

// middleware pour hasher le mot de passe
const hashPasswordMiddleware = async (
	req: Request,
	res: Response,
	next: NextFunction
) => {
	const { password } = req.body;

	try {
		const hashedPassword = await hashPassword(password);
		req.body.password = hashedPassword;
		next();
	} catch (error) {
		console.error(error);
		res.status(500).json({ message: "Internal server error" });
	}
};

export { authMiddleware, hashPasswordMiddleware };

Et maintenant, nous allons ajouter nos middlewares sur nos routes login & register.

// ./src/routes/auth.ts
import { Router } from "express";
const router = Router();

import { authAction } from "../actions/auth";
import {
	authMiddleware,
	hashPasswordMiddleware,
} from "../middlewares/authMiddleware";

router.post("/register", hashPasswordMiddleware, authAction.register);
router.post("/login", authMiddleware, authAction.login);

🔗 Liens utiles


Saison 5

📆 14/01/2025

📦 Récap du jour

Nous allons parler des tests aujourd'hui.

Il existe plusieurs types de tests :

  1. Test unitaire : permet de tester une fonction ou un module de manière isolée.
  2. Test d'intégration : permet de tester l'interaction entre plusieurs modules.
  3. Test end-to-end : permet de tester l'application dans son environnement de production.

Il existe plusieurs librairies pour faire des tests en JavaScript :

  • Jest
  • Mocha
  • Chai
  • Jasmine
  • ...

Nous allons voir comment faire des tests avec Jest.

Les tests unitaires

Les tests unitaires permettent de tester une fonction ou un module de manière isolée.

// ./src/add.ts
export const add = (a: number, b: number): number => a + b;
// ./src/add.test.ts
import { add } from "./add";

test("add", () => {
	expect(add(1, 2)).toBe(3);
});

Les tests d'intégration

Les tests d'intégration permettent de tester l'interaction entre plusieurs modules.

// ./src/add.ts
export const add = (a: number, b: number): number => a + b;
// ./src/subtract.ts
export const subtract = (a: number, b: number): number => a - b;
// ./src/add.test.ts
import { add } from "./add";
import { subtract } from "./subtract";

test("add and subtract", () => {
	expect(subtract(add(1, 2), 1)).toBe(2);
});

Les tests end-to-end

Les tests end-to-end permettent de tester l'application dans son environnement de production. Il y a plusieurs outils pour faire des tests end-to-end :

  • Cypress
  • Puppeteer
  • Playwright
  • ...

🔗 Liens utiles


📆 03/01/2025

📦 Récap du jour

Nous arrivons sur le dernier jour de la semaine avec l'apprentissage des middlewares.

middleware

Les middlewares

Les middlewares sont des fonctions qui vont s'exécuter entre la requête et la réponse.

// ./index.js
const middleware = (req, res, next) => {
	console.log("Je suis un middleware");
	next();
};

app.get("/", middleware, (req, res) => {
	res.send("Hello World !");
});

On reconnaît un middleware par le fait qu'il possède un 3ème paramètre next.

Ce next permet de passer à la fonction suivante.

// ./index.js
const middleware = (req, res, next) => {
	console.log("Je suis un middleware");
	next();
};

const middleware2 = (req, res, next) => {
	console.log("Je suis un middleware 2");
	next();
};

app.get("/", middleware, middleware2, (req, res) => {
	res.send("Hello World !");
});

Ici, les exemples sont simples, mais les middlewares sont très utiles pour vérifier des informations, par exemple, si un utilisateur est connecté ou non.

// ./index.js
const isLogged = (req, res, next) => {
	if (req.session.user) {
		next();
	} else {
		res.sendStatus(401);
	}
};

Ici, nous avons un middleware qui vérifie si l'utilisateur est connecté ou non.

🔗 Liens utiles


Saison 4

📆 02/01/2025

📦 Récap du jour

SQL AVANCÉ !! 😱

scream

Where

  • AND / OR
SELECT * FROM users
WHERE name = 'John' AND age = 25;
-- WHERE name = 'John' OR age = 25;
  • LIKE
    • Attention, inssensible à la casse
    • "%" : n'importe quel caractère
    • "a%" : commence par a
    • "%a" : fini par a
    • "%a%" : contient a
SELECT * FROM users
WHERE name LIKE 'J%';
  • BETWEEN
SELECT * FROM users
WHERE age BETWEEN 18 AND 25;
  • IS NULL / IS NOT NULL
SELECT * FROM users
WHERE age IS NULL;
SELECT * FROM users
WHERE age IS NOT NULL;

DISTINCT

Distinct permet de récupérer des valeurs uniques.

SELECT DISTINCT(name) FROM users;

FONTIONS

  • LENGTH
SELECT LENGTH(name) FROM users;
  • CONCAT
SELECT CONCAT(name, ' ', lastname) FROM users;

DATE

  • NOW
SELECT NOW() FROM users;
  • DATE_FORMAT
SELECT DATE_FORMAT(NOW(), '%d/%m/%Y') FROM users;

AGRÉGATION

  • COUNT
SELECT COUNT(*) FROM users;
  • MAX / MIN
SELECT MAX(age) FROM users;
SELECT MIN(age) FROM users;
  • AVG
SELECT AVG(age) FROM users;

GROUP BY

SELECT name, COUNT(*) FROM users
GROUP BY name;

HAVING

Having est un WHERE pour les agrégations. (ici, COUNT)

SELECT name, COUNT(*) FROM users
GROUP BY name
HAVING COUNT(*) > 1;

JOINTURE

il y a 3 types de jointures très utilisées :

  • (INNER) JOIN

ici, inner est entre parenthèse car c'est le type de jointure par défaut.

SELECT * FROM users
INNER JOIN posts ON users.id = posts.user_id;
  • LEFT JOIN
SELECT * FROM users
LEFT JOIN posts ON users.id = posts.user_id;
  • RIGHT JOIN
SELECT * FROM users
RIGHT JOIN posts ON users.id = posts.user_id;

join

🔗 Liens utiles


📆 17/12/2024

📦 Récap du jour

Nous avons ce matin les bases de données avec le monorepo js.

Les bases de données

  • DBAL (Database Abstraction Layer) : permet de communiquer avec la base de données.
  • ORM (Object-Relational Mapping) : permet de manipuler les données de la base de données comme des objets.

💡 Ce qui faut retenir

fullstack

Voilà notre architecture, un monorepo avec un client React et un serveur Express avec Node.js et une base de données MySQL.

Dans le détail:

fullstack

Si on zoom sur le serveur, on peut voir que nous avons plusieurs fichiers :

fullstack

🔗 Liens utiles


📆 16/12/2024

📦 Récap du jour

Les bases de la POO

Ce matin, nous avons vu la POO (Programmation Orientée Objet).

Nous avons vu plein de chose :

  • Les classes (en PascalCase)
    • class MyClass {}
  • Les méthodes (en camelCase)
    • sayHello() {}
  • Les propriétés
    • Publique: this.name = "John"
    • Privé: this.#lastname = "Doe"
  • Les constructeurs
  • constructor(name, lastname) {
    	this.name = name;
    	this.#lastname = lastname;
    }
  • super
    • super(name, lastname)
    • permet d'appeler le constructeur de la classe parente

poo

  • Les getters & setters
    • getName() {
      	return this.#name;
      }
      setName(name) {
      	this.#name = name;
      }
  • Les héritages
    • class MyClass extends MyOtherClass {}

🔗 Liens utiles


📆 13/12/2024

📦 Récap du jour

Nous allons voir comment fonctionne le monorepo.

sequenceDiagram
    box Web Client
    participant React as React
    participant Fetcher as Fetcher
    end
    box Web Server
    participant Express as Express
    participant Module as Module
    end
    box DB Server
    participant DB as MySQL Server
    end

    React-)Fetcher: event
    activate Fetcher
    Fetcher-)Express: requête (HTTP)
    activate Express
    Express-)Module: appel
    activate Module
    Module-)DB: requête SQL
    activate DB
    DB--)Module: données
    deactivate DB
    Module--)Express: json
    deactivate Module
    Express--)Fetcher: réponse HTTP
    deactivate Express
    Fetcher--)React: render
    deactivate Fetcher
Loading

Voilà l'architecture de notre monorepo.

C'est une architecture dite modulaire.

Mais qu'est-ce que c'est ?

L'architecture modulaire est une approche de conception logicielle qui divise un système en plusieurs modules indépendants qui peuvent être développés, testés et déployés séparément.

Pourquoi utiliser une architecture modulaire ?

  • Facilité de maintenance : Les modules sont indépendants les uns des autres, ce qui facilite la maintenance et la mise à jour du code.
  • Réutilisabilité du code : Les modules peuvent être réutilisés dans d'autres projets, ce qui permet de gagner du temps et de l'argent.
  • Sécurité : Les modules sont isolés les uns des autres, ce qui réduit les risques de failles de sécurité.

Le client

Vous le connaissiez déjà, c'est notre bon vieux React.

Le serveur

Nous avons utilisé Express pour créer notre serveur. Il est très simple à utiliser et très performant.

Nous ne pouvons pas tout expliquer ici, car c'est assez complexe. Mais si vous avez des questions, n'hésitez pas.

La base de données

Nous avons utilisé MySQL pour stocker nos données.

🔗 Liens utiles


📆 12/12/2024

📦 Récap du jour

Merise: Et oui, maintenant dans votre devlodex vous avez un nouveau mot !

Merise est une méthode de conception de base de données relationnelles.

Nous avons appris à faire un MCD (Modèle Conceptuel de Données) et un MLD (Modèle Logique de Données) & un MPD (Modèle Physique de Données).

Les relations et les cardinalités sont très importantes dans la conception d'une base de données et surtout, ils n'ont plus de secret pour vous !

image

💡 Ce qu'il faut retenir

Les cardinalités

Les cardinalités permettent de définir le nombre d'occurrences d'une entité qui peuvent être associées à une autre entité.

Il y a 3 types de cardinalités :

  • 1 : une seule occurrence.
  • 0 : aucune occurrence.
  • n : plusieurs occurrences.

Comment savoir si je met 0, 1 ou n ?

Admettons les entitées suivantes :

User & Role et la relation entre les deux est have.

erDiagram
    User ||--o{ Role : have
Loading

Nous nous posons la question suivante :

Un utilisateur a au minimum doit avoir un rôle, et un utilisateur a au maximum un rôle. Donc, la cardinalité est 11 du côté de l'utilisateur.

Ensuite pour le Role, un rôle peut être associé au minimum a aucun user et au maximum à plusieurs utilisateurs. Donc, la cardinalité est 0n du côté du rôle.

Les relations

Il y a 3 types de relations :

  • 1 to 1 : une seule entité est liée à une autre entité.
  • 1 to many : une entité est liée à plusieurs entités.
  • many to many : plusieurs entités sont liées à plusieurs entités.

Relation entre les cardinalités et les relations

1 to 1

  • Clé primaire vers n'importe quelle table pour être clé étrangère

1 to N | N to 1

  • La clé primaire cotée many passe étrangère coté one

N to N

  • Création d'un table de liaison

1 to many

1 to many

Many to many

many to many

Exemple complet détaillé

full_merise

MCD (Modèle Conceptuel de Données)

mcd

MLD (Modèle Logique de Données)

mld

MPD (Modèle Physique de Données)

mpd

🔗 Liens utiles


📆 10/12/2024

📦 Récap du jour

Nous avons enfin vu MySQL ! Vous allez pouvoir stocker vos données.

Mais pour ce faire, un petit rappel sur les bases de données relationnelles.

💡 Ce qu'il faut retenir

Structured Query Language ou SQL est un langage de manipulation de données, il permet de créer, de lire, de mettre à jour et de supprimer des données dans une base de données relationnelle.

Voilà une liste des commandes SQL :

Les commandes de bases

  • mysql -u <username> -p : permet de se connecter à mysql
  • CREATE DATABASE <database_name>; : permet de créer une base de données
  • SHOW DATABASES; : permet de voir les bases de données
  • USE <database_name>; : permet de sélectionner une base de données
  • SELECT DATABASE(); : permet de voir la base de données sélectionnée
  • SHOW TABLES; : permet de voir les tables d'une base de données
  • DESCRIBE <table_name>; : permet de voir les colonnes d'une table

D'autres commandes en vrac

  • CREATE TABLE <table_name> (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), age INT); : permet de créer une table
  • INSERT INTO <table_name> (name, age) VALUES ("John", 25); : permet d'insérer des données dans une table
  • SELECT * FROM <table_name>; : permet de voir toutes les données d'une table
  • TRUNCATE TABLE <table_name>; : permet de vider une table
  • DROP TABLE <table_name>; : permet de supprimer une table
  • UPDATE <table_name> SET name = "Mike" WHERE id = 1; : permet de modifier une donnée dans une table
  • DELETE FROM <table_name> WHERE id = 1; : permet de supprimer une donnée dans une table

Alter table

  • ALTER TABLE <table_name> ADD COLUMN <column_name> <type>; : permet d'ajouter une colonne dans une table
  • ALTER TABLE <table_name> MODIFY COLUMN <column_name> <type>; : permet de modifier une colonne dans une table
  • ALTER TABLE <table_name> DROP COLUMN <column_name>; : permet de supprimer une colonne dans une table sql

🔗 Liens utiles


📆 26/11/2024

📦 Récap du jour

Nous allons comprendre comment fonctionne une API (la suite de la semaine du 07/11).

Tout d'abord, nous avons créé un serveur avec Express (ultra minimaliste).

// index.ts

import express, { Request, Response } from "express";

const app = express();
const port = 3310;

app.get("/", (request: Request, response: Response) => {
	response.json({ message: "Hello World!" });
});

app.listen(port, () => {
	console.log(`Server is running on http://localhost:${port}`);
});

⬆️ ici, nous avons fait un serveur qui écoute sur le port 3310 et qui renvoie un objet JSON { message: "Hello World!" } quand on fait une requête sur la route /.

Voilà un exemple plus complet :

// index.ts

import express, { Request, Response } from "express";

const app = express();
const port = 3310;

app.get("/", (request: Request, response: Response) => {
	response.json({ message: "Hello World!" });
});

app.get("/users", (request: Request, response: Response) => {
	response.json([
		{ id: 1, name: "John" },
		{ id: 2, name: "Jane" },
		{ id: 3, name: "Bob" },
	]);
});

app.listen(port, () => {
	console.log(`Server is running on http://localhost:${port}`);
});

⬆️ ici, nous avons ajouté une route /users qui renvoie un tableau d'objets JSON.

[
	{ "id": 1, "name": "John" },
	{ "id": 2, "name": "Jane" },
	{ "id": 3, "name": "Bob" }
]

N'hésitez pas à tester avec Postman, Insomnia, Bruno, extension VSCode.

Coté client, nous savons déjà comment consommer une API avec fetch.

// index.ts

fetch("http://localhost:3310")
	.then((response) => response.json())
	.then((data) => console.log(data));

🔗 Liens utiles


Saison 3

📆 19/11/2024

📦 Récap du jour

Retour à React :D

Et cette fois-ci, nous allons voir la notion de Context.

Et oui, le context est très utile pour passer des données de composant en composant sans passer par les props.

Props drilling

props drilling

Context

context

L'avantage, c'est que l'on peut passer des données de composant en composant sans passer par les props.

// context/NameContext.js

// j'importe createContext depuis react ainsi que useState
import { createContext, useState } from "react";

// je crée mon context
const NameContext = createContext("");

// je crée mon provider
const NameContextProvider = ({ children }) => {
	const [name, setName] = useState("");

	const handleChange = (e) => {
		setName(e.target.value);
	};

	return (
		<NameContext.Provider value={{ name, handleChange }}>
			{children}
		</NameContext.Provider>
	);
};

export { NameContextProvider, NameContext };

Et pour l'utiliser

// main.jsx
// car je vais utiliser mon provider dans mon main

import ReactDOM from "react-dom/client";
import App from "./App.jsx";
// J'encapsule mon application dans le contexte NameContextProvider
// Maintenant, tous les composants de mon application ont accès au contexte NameContext
import { NameContextProvider } from "./context/NameContext.jsx";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(
	<React.StrictMode>
		<NameContextProvider>
			<App />
		</NameContextProvider>
	</React.StrictMode>
);

Le composant B2

// B2.jsx
import { useContext } from "react";
import { NameContext } from "../context/NameContext.jsx";
const B2 = () => {
	// Ici, je récupère le contexte NameContext
	// Je peux récupérer la valeur de name
	// grâce à la destructuration
	const { name } = useContext(NameContext);

	return (
		<div className="block">
			<h1>B2, and hello {name} 👋</h1>
		</div>
	);
};

export default B2;

🔗 Liens utiles


📆 07/11/2024

📦 Récap du jour

Les API ! C'est cool ! Mais c'est quoi une API ?

C'est quoi une API ?

Une API (Application Programming Interface) est un ensemble de règles et de protocoles qui permettent à des logiciels de communiquer entre eux.

Les types d'API

Il existe plusieurs types d'API :

  • API REST
  • API SOAP
  • API GraphQL
  • ...

Nous allons nous concentrer sur les API REST ✨ !

API REST pour Representational State Transfer est un style d'architecture qui définit un ensemble de contraintes pour la création de services web.

rest

Les méthodes HTTP

Les méthodes HTTP sont des verbes qui permettent de définir l'action à effectuer sur une ressource. Il y a une méthode pour chaque action.

Méthode HTTP Action Description
POST CREATE Créer une entrée
GET READ Récupérer une information
PUT UPDATE Mettre à jour une information
DELETE DELETE Supprimer un élément

Les codes de statut HTTP

Les codes de statut HTTP sont des codes numériques qui indiquent le résultat d'une requête HTTP. Il y a pleins de catégories de codes :

  • 1xx : Information
  • 2xx : Succès
  • 3xx : Redirection
  • 4xx : Erreur client
  • 5xx : Erreur serveur

Consommer une API en JS

Pour consommer une API en JS, il faut utiliser la méthode fetch().

fetch("https://api.exemple.com")
	.then((response) => response.json())
	.then((data) => console.log(data));

En mode async/await, ça donne ça :

async function fetchData() {
	const response = await fetch("https://api.exemple.com");
	const data = await response.json();
	console.log(data);
}

Le mot clé async permet de définir une fonction asynchrone. Une fonction asynchrone est une fonction qui retourne une Promise. Le mot clé await permet de mettre en pause l'exécution d'une fonction asynchrone jusqu'à ce qu'une Promise soit résolue.

JSON

Le JSON (JavaScript Object Notation) est un format de données textuelles qui est facile à lire et à écrire pour les humains.

{
	"key": "value",
	"key2": "value2"
}

🔗 Liens utiles


📆 06/11/2024

📦 Récap du jour

Nous allons pas écrire grand chose pour ce jour car ce n'est pas une généralité mais quand même, nous allons parler du workflow git de la Wild.

Le workflow git de la Wild

Nous allons avoir 3 branches disctinctes :

  • main 🔐 : c'est la branche qui contient le code de production, c'est à dire le code qui est en ligne.
  • staging 🔐 : c'est la branche qui contient le code de préprod, c'est à dire le code qui simule celui qui est en ligne.
  • dev 🔐 : c'est la branche qui contient le code de développement, c'est à dire le code qui est en cours de développement.
  • features : c'est la branche qui contient le code de la feature que vous êtes en train de développer.

Nommage des branches

Nous vous conseillons d'appeler vos branches de la manière suivante :

  • <N° du sprint><N° de l'US>_<Ma feature>

Ex :

  • S01US01_navbar
  • S02US12_contact_form

Quand je suis content, je commit

Nous vous conseillons de faire un commit à chaque fois que vous avez fini une tâches technique.

  • HTML
  • Style
  • Validation

Par exemple.

Les labels

Nous vous quelques labels pour définir l'état de votre US.

  • REVIEWED
  • CHANGES REQUESTED
  • CORRECTIONS DONE
  • CONFLICTS
  • CONFLICTS RESOLVED

🔗 Liens utiles


📆 05/11/2024

Nous avons fait un petit cours sur la méthodologie Agile avec le framwork Scrum.

Nous n'allons pas faire un gros récap, car le cours est assez long.

Mais en gros, pourquoi choisir la méthodologie Agile dans un projet ?

what-is-the-difference-between-agile-and-waterfall-model.png (750×500)

Regardé le cours, et si vous avez des questions, n'hésitez pas. (J'ai aussi mis un lien vers mon cours sur github)

📦 Récap du jour

agile

🔗 Liens utiles


Saison 2

📆 31/10/2024

🚨 Nouvelle notion ! 🚨

Et oui, nous avons appris le nouveau hook useEffect aujourd'hui !

💡 ce qu'il faut retenir

  • useEffect prend en paramètres :
    • une fonction qui va être exécutée à chaque fois que le composant est rendu.
    • tableau de dépendances, ce tableau permet de définir quand la fonction va être exécutée.

Concernant le tableau de dépendances, il est possible de définir :

  • rien : la fonction va être exécutée à chaque fois que le composant est rendu.
  • [] : la fonction va être exécutée une seule fois, au moment du rendu du composant.
  • [value] : la fonction va être exécutée à chaque fois que la valeur de value change.
import { useEffect } from "react";

function App() {
	useEffect(() => {
		console.log("render");
	}, []);

	return <div>App</div>;
}

Le hook useEffect peut être utilisé pour effectuer différentes tâches, telles que :

  • Récupérer des données depuis une API et mettre à jour l'état du composant en conséquence
  • Abonner le composant à des événements (ex : clics de souris, mouvements de la souris, frappes de clavier, etc.)
  • Mettre à jour le DOM pour refléter les changements d'état du composant Nettoyer les effets de bord, tels que les abonnements aux événements, les connexions à des API, etc.

Il est important de noter que le hook useEffect doit être utilisé avec prudence, car il peut entraîner des effets de bord indésirables s'il est mal utilisé. Il est recommandé de ne pas exécuter de code coûteux dedans

En résumé, le hook useEffect est un outil puissant pour gérer les effets de bord dans les composants React. Il peut être utilisé pour exécuter une logique après le rendu d'un composant, telle que la récupération de données depuis une API, l'abonnement à des événements, la mise à jour du DOM, etc.

🔗 Liens utiles


📆 30/10/2024

Ce matin, il y avait un atelier sur react-router-dom.

Il y a beaucoup de texte, mais dans tout ça, il faut retenir que react-router-dom est une librairie qui permet de gérer la navigation dans une application React.

Installation

Pour installer react-router-dom, il faut taper la commande suivante :

$ npm install react-router-dom

Les instructions d'importation

  • createBrowserRouter : permet de créer un contexte de navigation, il contient toute la logique de navigation.
  • Link : permet de créer un lien vers une autre page. (Celle ci ne recharge pas la page)
  • RouterProvider : permet de fournir le contexte de navigation à l'application.
import { createBrowserRouter, RouterProvider } from "react-router-dom";

const router = createBrowserRouter([
	{
		// le chemin de l'URL, ici `/`
		path: "/",
		element: (
			<>
				<nav>
					<Link to="/">Home</Link>
					<Link to="/about">About</Link>
				</nav>
				<main>
					// le composant à afficher, bien sûr, il faut l'importer
					<Home />
				</main>
			</>
		),
	},
	{
		// le chemin de l'URL, ici `/about`
		path: "/about",
		element: (
			<>
				<nav>
					<Link to="/">Home</Link>
					<Link to="/about">About</Link>
				</nav>
				<main>
					// le composant à afficher, bien sûr, il faut l'importer
					<About />
				</main>
			</>
		),
	},
]);

Comment rendre ça plus propre ?

Nous pouvons créer un composant Layout qui va contenir la navigation et le composant à afficher.

Ce composant Layout sera la base de notre application, son affichage ne changera pas.

Pour pouvoir passer un composant différent en fonction de l'URL, nous allons utiliser le composant Outlet.

  • Outlet : permet d'afficher le composant correspondant à l'URL.

Voilà à quoi ressemble notre Layout :

// Layout.jsx
import { Link, Outlet } from "react-router-dom";

function Layout() {
	return (
		<>
			<nav>
				<Link to="/">Home</Link>
				<Link to="/about">About</Link>
			</nav>
			<main>
				<Outlet />
			</main>
		</>
	);
}

export default Layout;

Maintenant que nous avons notre Layout, nous pouvons l'utiliser dans notre router.

import { createBrowserRouter, RouterProvider } from "react-router-dom";

// router creation
const router = createBrowserRouter([
	{
		path: "/",
		element: <Layout />,
		children: [
			{
				path: "/",
				element: <Home />,
			},
			{
				path: "/about",
				element: <About />,
			},
		],
	},
]);

Oh, un nouveau mot clé children est apparu, il permet de définir les routes enfants. C'est à dire les routes qui sont dans le Layout.

Dans notre exemple, / possède le composant <Home /> et va donc être affiché dans le Layout à la place de <Outlet />. La même chose pour /about.

Si je souhaite avoir une route qui n'est pas dans le Layout, je peux la définir en dehors.

outlet

const router = createBrowserRouter([
	{
		path: "/",
		element: <Layout />,
		children: [
			{
				path: "/",
				element: <Home />,
			},
			{
				path: "/about",
				element: <About />,
			},
		],
	},
	{
		path: "/contact",
		element: <Contact />,
	},
]);

Si vous souhaitez avoir une route "dynamique", alors, vous pouvez utiliser les paramètres.

const router = createBrowserRouter([
	{
		path: "/",
		element: <Layout />,
		children: [
			{
				path: "/",
				element: <Home />,
			},
			{
				path: "/about",
				element: <About />,
			},
			{
				path: "/user/:id",
				element: <User />,
			},
		],
	},
]);

Pour récupérer le paramètre, vous pouvez utiliser useParams().

// User.jsx

import { useParams } from "react-router-dom";

function User() {
	// Ici, useParams est un hook qui permet de récupérer les paramètres de l'URL
	// Dans notre cas, on récupère l'id. l'"id" est la clé que nous avons défini dans la route
	const { id } = useParams();

	return <h1>User {id}</h1>;
}

🔗 Liens utiles


📆 29/10/2024

📦 Récap du jour

Nous avons fait un petit projet de trombinoscope avec React. Nous avons vu comment créer un composant, comment passer des props, comment utiliser des hooks, etc. Le replay est disponible.

🔗 Liens utiles


📆 28/10/2024

📦 Récap du jour

Nous avons fait toutes les quêtes pokémons pour comprendre toutes les subtilités entre props, state, partage de state, etc.

Pour rappel

Un state est contenu dans un composant, il est propre à ce composant. Il est donc IMPOSSIBLE de le partager entre plusieurs composants.

state

Pour certaine raison, il est essential de partager un state entre plusieurs composants. Pour cela, il faut remonter le state au composant parent le plus proche.

state

Dans le cas ci dessus, nous allons passer en props le state message dans le composant Messages (<Messages text={message} />) et dans le composant Input (<Input setMessage={setMessage} />).

Du coup, le composant Messages et Input ont accès au state message.

🔗 Liens utiles


📆 24/10/2024

📦 Récap du jour

Aujourd'hui, nous allons apprendre encore un truc de ouf ! Les hooks ! Et plus particulièrement le hook useState !

useState

Le hook useState permet de gérer le state dans un composant de type fonction.

Son utilité est de pouvoir modifier la valeur d'une variable sans avoir à recharger la page.

Vous voulez un exemple ? Et bien en voilà un !

// Composant
// App.jsx

// j'importe useState depuis react
import React, { useState } from "react";

function App() {
	// On initialise la variable count à 0
	// structure :
	// const [variable, fonction] = useState(valeur)
	const [count, setCount] = useState(0);

	return (
		<div className="App">
			<h1>{count}</h1>

			{/* On utilise la fonction setCount pour modifier la valeur de count
				seul setCount permet de modifier la valeur de count, count est en lecture seule.
				Ça permettra de modifier la valeur de count sans recharger la page mais uniquement le composant.
				*/}
			<button onClick={() => setCount(count + 1)}>+</button>
		</div>
	);
}

Dans l'exemple ci dessus, nous avons une variable count qui est initialisée à 0 et une fonction setCount qui permet de modifier la valeur de count.

Bien sûr, vous pouvez avoir plusieurs variables et fonctions dans un composant.

// Composant
// App.jsx

import React, { useState } from "react";

function App() {
	const [count, setCount] = useState(0);
	const [name, setName] = useState("John");

	return (
		<div className="App">
			<h1>{count}</h1>
			<h1>{name}</h1>

			<button onClick={() => setCount(count + 1)}>+</button>
			<button onClick={() => setCount(count - 1)}>-</button>

			<button onClick={() => setName("Mike")}>Change name</button>
		</div>
	);
}

useState est asynchrone

Et oui, useState est asynchrone, c'est à dire que si vous faites ça :

// Composant
// App.jsx

import React, { useState } from "react";

function App() {
	const [count, setCount] = useState(0);

	return (
		<div className="App">
			<h1>{count}</h1>

			<button onClick={() => setCount(count + 1)}>+</button>
			<button onClick={() =>
				setCount(count - 1)
				console.log(count)
			}>-</button>
		</div>
	);
}

Et bien, le console.log(count) ne sera pas à jour, car useState est asynchrone. C'est à dire que le console.log va s'exécuter avant que la valeur de count soit modifiée.

Si je souhaite faire par exemple, soustraire 2 à count, je dois faire comme ça :

// Composant
// App.jsx

import React, { useState } from "react";

function App() {
	const [count, setCount] = useState(0);

	return (
		<div className="App">
			<h1>{count}</h1>

			<button onClick={() => setCount(count + 1)}>+</button>
			<button
				onClick={() => {
					setCount((prev) => prev - 1);
					setCount((prev) => prev - 1);
				}}
			>
				-
			</button>
		</div>
	);
}
💡 Et avec les classes, comment fonctionne les states ?

Les states avec les classes

A l'origine, les states sont apparus avec les classes. C'est uniquement depuis la version 16.8 de React que l'on peut utiliser les hooks dans les composants de type fonction.

Donc, pour utiliser les states avec les classes, il faut faire comme ça :

// Composant
// App.jsx

import React, { Component } from "react";

class App extends Component {
	// On initialise le state dans le constructor
	constructor(props) {
		super(props);
		this.state = { count: 0 };
		// On bind la fonction increment
		// pour que le this soit accessible dans la fonction
		this.increment = this.increment.bind(this);
	}
	increment() {
		const { count } = this.state;
		this.setState({ count: count + 1 });
	}
	render() {
		const { count } = this.state;
		return <button onClick={this.increment}>{count}</button>;
	}
}

🔗 Liens utiles


📆 23/10/2024

props

Les props sont des arguments passés à un composant React.

On passe TOUJOURS les props de parent à enfant.

// src/App.js
import Welcome from "./components/Welcome";

function App() {
	return (
		<div>
			<Welcome name="Hermione" />
			<Welcome name="Ron" />
			<Welcome name="Harry" />
		</div>
	);
}

Props est un objet qui contient les propriétés passées à un composant.

// src/components/Welcome.js
function Welcome(props) {
	console.log(props);
	/* ex: { name: "Hermione" }  */
	return <h1>Hello, {props.name}</h1>;
}

Pour briller en société

La destructuration

La destructuration permet de récupérer une valeur d'un objet ou d'un tableau.

Dans notre exemple, voilà comment on peut faire :

// src/components/User.jsx

function User(props) {
	const { firstname } = props;
	return (
		<div>
			<h1>{firstname}</h1>
		</div>
	);
}

// OU cette façon qui est plus utilisée

function User({ firstname }) {
	return (
		<div>
			<h1>{firstname}</h1>
		</div>
	);
}

Un petit rappel

Les retours (return) implicites en JS

// return implicite
const sum = (a, b) => a + b;

// syntaxe classique
const multiply = (a, b) => {
	return a * b;
};

console.log(sum(5, 7));
console.log(multiply(2, 2));

🔗 Liens utiles


📆 22/10/2024

📦 Récap du jour

dance

REACT 👏👏👏

REACT 👏👏👏

REACT 👏👏👏

Et oui, nous entamons la partie React de notre formation.

Alors qu'avons-nous vu aujourd'hui ?

💡Ce qu'il faut retenir

C'est quoi React ?

React est une bibliothèque JavaScript pour la construction d'interfaces utilisateur.

Pourquoi React ?

  • Facile à apprendre : React est facile à apprendre, surtout si vous avez des connaissances en HTML, CSS et JavaScript.
  • Réutilisable : React vous permet de créer des composants réutilisables.
  • Performant : React utilise une technique appelée DOM virtuel qui améliore les performances de l'application.

JSX

JSX est une extension de la syntaxe JavaScript qui permet d'écrire du HTML dans du JavaScript. Alors le JSX ça ressemble à l'html, à l'odeur, à la couleur, mais ce n'est pas de l'html.

const element = <h1>Hello, world!</h1>;

Les composants

Les composants sont les éléments de base de React. Ils permettent de diviser l'interface utilisateur en morceaux indépendants et réutilisables.

function Welcome() {
	return <h1>Hello world!</h1>;
}

🔗 Liens utiles

Le cours viendra plus tard, car il est assez long et je ne veux pas vous spoiler. 😎


Saison 1

📆 15/10/2024

📦 Récap du jour

Node.js, c'est quoi ? C'est un environnement d'exécution JavaScript côté serveur.

Node.js est basé sur le moteur JavaScript V8 de Chrome.

Comment ça marche ?

Pour utiliser Node.js, il faut installer Node.js sur votre machine => Node.js

Ensuite, vous pouvez écrire du code JavaScript dans un fichier .js et l'exécuter avec Node.js.

$ node
> console.log("Hello World !");

Pas terrible comme utilisation, du coup, nous allons utiliser plutôt un fichier.

// index.js
console.log("Hello World !");
$ node index.js
# output
Hello World !

NPM

NPM (Node Package Manager) est un gestionnaire de paquets pour Node.js.

Il permet d'installer des paquets (bibliothèques) pour Node.js.

$ npm install chalk@4.1.2

Détail de la commande :

  • npm : le gestionnaire de paquets
  • install : commande pour installer un paquet
  • chalk : le nom du paquet
  • @4.1.2 : la version du paquet

Je prend la version 4.1.2 de chalk car la version 5 ou plus utilise ESM (ECMAScript Modules) et je ne veux pas vous embrouiller avec ça.

// index.js
const chalk = require("chalk");

console.log(chalk.blue("Hello World !"));

🔗 Liens utiles


📆

📦 Récap du jour

Comment faire une bonne démo voilà le thème abordé aujourd'hui.

Nous avons vu ce qu'il fallait faire et ne pas faire lors d'une démo. ⬇️

  • N’attendez pas la dernière minute
  • Soyez clair et concis
  • Appuyez-vous sur votre support
  • Adaptez-vous à votre interlocuteur
  • Préparez la répartition de la parole
  • Anticipez les questions / réponses
  • Entraînez-vous !!!!!

🔗 Liens utiles


📆 10/10/2024

Partie 2

📦 Récap du jour

Encore rien de nouveau, mais ça ne fait pas de mal 😎

N'hésite pas à aller au 08/10/2024, c'est quasiment le même cours.

💡 Pour briller en société

Optional chaining

L'opérateur de chaînage optionnel ?. permet de lire la valeur d'une propriété située au sein d'une chaîne de connexion avec une valeur null ou undefined sans lever d'erreur.

let user = {}; // l'utilisateur est sans nom

alert(user?.address?.street); // undefined (pas d'erreur)

Alors que sans l'opérateur de chaînage optionnel, nous aurions une erreur :

let user = {}; // l'utilisateur est sans nom

alert(user.address.street); // Erreur !

Arrow function

Les fonctions fléchées sont des raccourcis pour déclarer des fonctions.

// syntaxe
// ici, en plus de la syntaxe, nous avons un return implicite
let sum = (a, b) => a + b;

/* équivalent à */

let sum = function (a, b) {
	return a + b;
};

La différence entre classic function & arrow function

const user = {
	name: "anthony",
	classicFunction: function () {
		console.log(this, this.name);
	},
	arrowFunction: () => {
		console.log(this, this.name);
	},
};

user.classicFunction();
user.arrowFunction();

/**********/
/* output */
/**********/

// {name: "anthony", classicFunction: ƒ, arrowFunction: ƒ} "anthony"

// Window {window: Window, self: Window, document: document, name: "", location: Location, …} undefined

Ce que ça veut dire, c'est que les fonctions fléchées n'ont pas de this propre, elles prennent le this de leur parent.

ET SURTOUT ! JAVA !== JAVASCRIPT

code java pour un hello world:

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, World");
  }
}

code javascript pour un hello world:

console.log("Hello, World");

Alors, c'est plus simple JS non ? 😉

🔗 Liens utiles


📆 09/10/2024

Partie 1

📦 Récap du jour

Bon, rien de trop nouveau sous le soleil. Mais on quand même vu les bases.

N'hésite pas à aller au 08/10/2024, c'est quasiment le même cours.

Comment fonctionne la balise script

script script script

💡 Pour briller en société

IIFE

Ici, nous avons une fonction qui s'appel et s'execute directement. On appelle ça une IIFE (Immediately Invoked Function Expression).

//IIFE

(function () {
	//code
})();

🔗 Liens utiles


📆 08/10/2024

📦 Récap du jour

✨ Enfin la manipulation du DOM ✨

noo

Ce qu'il faut retenir

Le DOM (Document Object Model) est une interface de programmation pour les documents HTML.

Il représente la page web sous forme d'arbre d'objets.

Nous avons besoins de 3 étapes pour manipuler le DOM :

  1. Sélectionner un élément
  2. Ajouter un événement
  3. Modifier le contenu

Sélectionner un élément

Il existe plusieurs façons de sélectionner un élément :

  • document.getElementById('id')
  • document.getElementsByClassName('class')
  • document.getElementsByTagName('tag')

Moi je préfère utiliser les méthodes suivantes :

  • document.querySelector('selecteur')
  • document.querySelectorAll('selecteur')

Si vous avez appris a utiliser les sélecteurs CSS, vous serez à l'aise avec ces méthodes.

  • #id : sélectionne un élément par son id
    • document.querySelector('#id')
  • .class : sélectionne un élément par sa classe
    • document.querySelector('.class')
  • tag : sélectionne un élément par sa balise
    • document.querySelector('tag')

Ajouter un événement

Il existe plusieurs type d'événements :

  • click : au clic
  • change : à la modification
  • mouseover : au survol
  • ...

Modifier le contenu

Il existe plusieurs manière de modifier le contenu :

  • innerHTML : permet de modifier le contenu HTML
  • textContent : permet de modifier le contenu textuel
  • setAttribute : permet de modifier un attribut
  • style : permet de modifier le style
  • ...

🔗 Liens utiles


📆 04/10/2024

📦 Récap du jour

LES BASES PROGRAMMATIONS

gif

Alors, oui, c'est assez dur, il y a plein de choses à connaître, mais en vrai. Çaaa vaaaaa !

Les éléments communs pour tout le monde :

Les variables

Une variable est un espace mémoire qui permet de stocker une valeur.

let maVariable = "Hello World !";

Attention, quand une variable est réassignée, elle perd sa valeur précédente.

let prenom = "anthony";

prenom = "bob";

anthony est remplacé par bob.

variable

Les types de données

Il existe plusieurs types de données :

Les primitifs :

  • string : chaîne de caractères
  • number : nombre
  • boolean : vrai ou faux
  • null : nul
  • undefined : non défini
  • ...

Les non primitifs :

  • object : objet
  • array : tableau
  • function : fonction
  • ...

Les opérateurs

Il y a les opérateurs mathématiques que vous connaissez déjà, mais il y en a d'autres.

Voilà le lien pour les opérateurs : Opérateurs

Les tableaux

Les tableaux permettent de stocker plusieurs valeurs.

let monTableau = [2, "Hello", true, ["coucou"]];

Il existent plusieurs méthodes pour manipuler les tableaux :

  • push() : ajoute un élément à la fin du tableau
  • pop() : supprime le dernier élément du tableau
  • shift() : supprime le premier élément du tableau
  • unshift() : ajoute un élément au début du tableau

Les conditions

Les conditions permettent de faire des choix dans le code.

L'architecture d'un if/else:

// Une condition doit obligatoirement se répondre par true ou false
if (condition) {
	// code
} else if (condition) {
	// code
} else {
	// code
}

Ex:

let maVariable = "Bouh";

if (maVariable === "Hello World !") {
	console.log("C'est cool !");
} else {
	console.log("C'est pas cool !");
}

💡 Astuce !

Si votre condition est un booléen (true ou false), vous pouvez faire comme ça :

let maVariable = true;

if (maVariable) {
	console.log("C'est cool !");
} else {
	console.log("C'est pas cool !");
}

Ou encore :

if (!maVariable) {
	console.log("C'est pas cool !");
} else {
	console.log("C'est cool !");
}

Les boucles

Les boucles permettent de répéter une action.

Il y a 3 informations importantes :

  • L'initialisation
  • La condition d'arrêt
  • L'incrémentation

Boucle for:

for (let i = 0; i < 10; i++) {
	console.log(i);
}

Boucle while & do while: (attention à ne pas faire de boucle infinie !)

let i = 0;

while (condition) {
	// code

	i++;
}
let i = 0;

do {
	// code
	i++;
} while (condition);

Il existe tout un tas d'autre façon de boucler, mais ce sont les plus courants.

Les fonctions

Les fonctions permettent de réutiliser du code.

La syntaxe :

fonction

  • function : mot clé pour déclarer une fonction
  • maFonction : nom de la fonction
  • () : les paramètres
  • {} : le corps de la fonction
function maFonction() {
	console.log("Hello World !");
}

/* réutilisation de la fonction maFonction */
maFonction();
maFonction();

fonction

⚠️ Attention, une fonction qui ne fait qu'un console.log() ne sert à rien ! Il faut que la fonction retourne (return) une valeur.

function maFonction() {
	return "Hello World !";
}

Et pour récupérer la valeur de la fonction :

let maVariable = maFonction();
Un exemple qui regroupe plein d'info 😎
// ma variable students qui est un tableau d'étudiants
const students = [
	"Camille G",
	"Marc",
	"Manon",
	"Elodie",
	"Antoine",
	"Nabil",
	"Julie",
	"Camille L",
	"Joey",
	"Charles",
	"Thomas",
	"Frank Sena",
	"Ryan",
	"Rudy",
];

// une fonction sayHello qui prend 1 paramètre `name`
function sayHello(name) {
	console.log("Coucou " + name + " 👋");
}

// Une boucle for qui commence à 0 jusqu'à la taille du tableau
for (let i = 0; i < students.length; i += 1) {
	// utilisation de la fonction sayHello qui prend un argument
	// students[i] qui vaut le prénom de mon tableau "students" à l'index `i`
	sayHello(students[i]);
}

🎁 Les 6 falsy values

Les 6 falsy values sont des valeurs qui sont évaluées à false dans une condition.

  • false
  • 0
  • ""
  • null
  • undefined
  • NaN

Si vous voulez en savoir plus, voici un article qui en parle : Les 6 falsy values

🔗 Liens utiles


📆 03/10/2024

📦 Récap du jour

C'est quoi git & github ❓

Git est un logiciel de versionning, c'est à dire qu'il permet de gérer les versions de notre code, il est en local.

Github est un service en ligne qui permet de stocker notre code en ligne.

Les commandes de bases

commande description
git init permet d'initialiser un repo git
git add . permet d'ajouter tous les fichiers au stage
git commit -m "message" permet de créer un commit
git push permet d'envoyer le code sur github
git pull permet de récupérer le code sur github
git status permet de voir l'état du repo git
git checkout permet de changer de branche
git switch depuis la version 2.23
git branch permet de créer une branche

git

Si vous souhaitez avoir un git cheat sheet, voici le lien : Git Cheat Sheet

gitGraph
   commit
   commit
   branch develop
   checkout develop
   commit
   commit
   checkout main
   merge develop
   commit
   commit
Loading

Ensuite, à vous l'atelier git & github !

🔗 Liens utiles




📆 01/10/2024

📦 Récap du jour

Nous avons vu aujourd'hui comment passer des wireframes papier vers un prototype sur figma ainsi que les bonnes pratiques UX/UI.

Pour rappel :

🔗 Liens utiles




📆 27/09/2024

📦 Récap du jour

Notre petit cours d'aujourd'hui était sur les bases du web. Le principe est de comprendre comment fonctionne le web, et ainsi, faire la différence entre le web et internet.

💡Ce qu'il faut retenir

Web

Le web est un système de publication et de consultation de documents hypertextes liés entre eux et accessibles via le réseau internet.

Internet

Internet est un réseau informatique mondial accessible au public. Il permet de partager des informations et des ressources.

Protocoles

  • HTTP(S) : Hypertext Transfer Protocol (Secure)
  • FTP : File Transfer Protocol
  • etc.

Navigateur

Un navigateur web est un logiciel permettant de consulter des pages web. Les plus connus sont Chrome, Firefox, Safari, Edge, Opera.

URL

Une URL (Uniform Resource Locator) est une adresse web. Elle est composée de plusieurs éléments :

  • Protocole : http:// ou https://
  • Nom de domaine : www.google.com
  • Chemin : /search?q=hello+world

Bonus

ipv4 ipv6

🔗 Liens utiles


📆 26/09/2024

📦 Récap du jour

Nouvelle connaissance débloquée : Le Terminal.

giphy

Oui, le terminal est un outil puissant, mais il peut être intimidant au début. C'est pourquoi nous avons vu les bases pour vous aider à vous familiariser avec cet outil.

💡Ce qu'il faut retenir

Le kit de survie du terminal :

Commande Description
pwd affiche le répertoire courant
ls liste les fichiers et dossiers du répertoire courant
cd change de répertoire
mkdir crée un dossier
touch crée un fichier
rm supprime un fichier
rm -r supprime un dossier
mv déplace un fichier ou un dossier
cp copie un fichier ou un dossier
cat affiche le contenu d'un fichier
echo affiche un message à l'écran
clear efface le terminal
. répertoire courant
.. répertoire parent
man affiche le manuel d'une commande
history affiche l'historique des commandes

Bien sûr, il y a beaucoup plus de commandes, mais ce sont les bases pour commencer.

🔗 Liens utiles



📆 25/09/2024

📦 Récap du jour

Ladies and gentlemen, aujourd'hui, nous avons vu les bases du responsive design.

woaw

Le responsive, c'est la capacité d'un site web à s'adapter à la taille de l'écran de l'utilisateur. C'est un élément essentiel pour un site web, car il est important que le site soit lisible sur tous les supports.

Nous avons parler des grids et flexbox, qui sont des outils de mise en page en CSS. Ils permettent de créer des mises en page complexes et de les rendre responsive.

💡Ce qu'il faut retenir

Voilà un petit récap des breakpoints (points de rupture) les plus utilisés :

img

🔗 Liens utiles



📆 24/09/2024

📦 Récap du jour

Aujourd'hui, nous avons vu les bases de l'HTML et du CSS et comment lier les deux.

Je tiens à vous rassurer, il n'est pas nécessaire de tout retenir, mais il est important de comprendre les concepts de base.

💡Ce qu'il faut retenir

  • HTML : c'est la structure de la page web
    • Les balises HTML sont des éléments de structure
      • <h1></h1> : titre de niveau 1
      • <p></p> : paragraphe
      • <a></a> : lien
      • <img /> : image
      • etc.
  • CSS : c'est la mise en forme de la page web
    • Les sélecteurs CSS permettent de cibler des éléments HTML
      • h1 : cible tous les titres de niveau 1
      • .ma__classe : cible tous les éléments ayant la classe class="ma__classe"
      • #mon__id : cible l'élément ayant l'id id="mon__id"
<!DOCTYPE html>
<html>
	<head>
		<title>Nom de mon site</title>
		<link rel="stylesheet" type="text/css" href="./style.css" />
	</head>
	<body>
		<h1>Titre de la page</h1>
		<p>Un paragraphe</p>
	</body>
</html>
h1 {
	color: blue;
	font-size: 12px;
}

Priorité des sélecteurs (spécificité) L'ordre de priorité des sélecteurs est important :

  • Sélecteur d'ID (#id) : Priorité la plus élevée.
  • Sélecteur de classe (.classe) : Priorité moyenne.
  • Sélecteur de balise (balise) : Priorité la plus basse.

Concernant les propriétés CSS, il est important de comprendre qu'il est impossible de toutes les retenir. C'est pourquoi il est essentiel de savoir où trouver les informations. L'anglais est un atout pour la programmation, car la majorité des ressources sont en anglais.

🔗 Liens utiles




📆 23/09/2024

📦 Récap du jour

Aujourd'hui c'est présentation ! Vous avez eu un aperçu de ce qui vous attend dans les prochains mois.

Vous avez même eu le mot du CEO de la Wild Code School !

Nous avons aussi pris une superbe photo de groupe ! 📸

crew

🔗 Liens utiles


About

No description, website, or topics provided.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors