Wat Gaan We Maken?
We bouwen een compleet registratie en login systeem met 2 pagina's:
- Register pagina - nieuwe gebruikers aanmaken (eerste stap!)
- Login pagina - inloggen met bestaand account
Hoe werkt de flow?
Nieuwe gebruiker
|
v
/register - Roep register() aan uit AuthContext
|
| AuthContext slaat account op in localStorage["users"]
|
v
/login - Roep login() aan uit AuthContext
|
| AuthContext checkt credentials in localStorage["users"]
| Bij succes: zet user in state + localStorage["user"]
|
v
/dashboard - Gebruiker is ingelogd!
|
| AuthContext weet wie ingelogd is
|
v
Refresh? → Nog steeds ingelogd! (AuthContext leest localStorage["user"])
Belangrijk: Dit is een simpele versie met localStorage. Voor een echte app heb je een backend nodig met een database! Passwords worden nu in plain text opgeslagen - dit is ALLEEN voor oefenen.
Wat gaan we bouwen?
- Register form - gebruik
register()uit AuthContext - Login form - gebruik
login()uit AuthContext - Feedback - toon success/error berichten aan de gebruiker
- Navigatie - stuur gebruiker automatisch naar de juiste pagina
Het voordeel: We hoeven niet zelf met localStorage te werken! AuthContext doet al het werk. We roepen alleen de functies aan.
Start met de Register pagina hieronder - je moet eerst een account hebben voordat je kunt inloggen!
Register Page - Stap 1: Account Aanmaken
Voordat iemand kan inloggen, moet er eerst een account zijn! Daarom beginnen we met de register pagina.
Wat doet deze pagina?
1. Gebruiker vult username en password in
2. We roepen register() aan uit AuthContext
3. AuthContext checkt of username al bestaat en slaat account op
4. Bij succes: gebruiker wordt doorgestuurd naar login pagina
Maak een nieuw bestand: src/pages/Register.jsx
import { useState, useContext } from "react";
import { useNavigate } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";
function Register() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const { register } = useContext(AuthContext);
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
// Check of velden zijn ingevuld
if (!username || !password) {
setError("Vul alle velden in!");
return;
}
// Roep register functie aan uit AuthContext
const result = register(username, password);
if (result.success) {
// Succes! Ga naar login
alert(result.message); // "Account aangemaakt!"
navigate("/login");
} else {
// Er ging iets mis
setError(result.message); // "Username bestaat al!"
}
};
return (
<div className="auth-container">
<h1>Registreren</h1>
<form onSubmit={handleSubmit}>
<div>
<label>Username:</label>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div>
<label>Password:</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
{error && <p className="error">{error}</p>}
<button type="submit">Registreren</button>
</form>
<p>
Al een account? <a href="/login">Log hier in</a>
</p>
</div>
);
}
export default Register;
Veel simpeler!
We hoeven niet zelf met localStorage te werken. De register() functie uit AuthContext doet al het werk voor ons!
Wat gebeurt er?
- User vult username en password in
- We roepen
register(username, password)aan - AuthContext checkt of username al bestaat
- AuthContext slaat het account op in localStorage["users"]
- We krijgen
{ success: true/false, message: "..." }terug - Bij succes: navigate naar /login
- Bij fout: toon error message
Security warning:
Passwords worden in PLAIN TEXT opgeslagen! Dit is ALLEEN voor oefenen. In een echte app moet je passwords hashen met een backend!
Wat gebeurt er als je probeert in te loggen zonder eerst te registreren?
Dan zie je de error: "Verkeerde username of password!"
Want er staan nog geen users in localStorage["users"]. Je MOET eerst registreren voordat je kunt inloggen.
Login Page - Stap 2: Inloggen met Bestaand Account
Nu de gebruiker een account heeft (via register), kunnen ze inloggen!
Wat doet deze pagina?
1. Gebruiker vult username en password in
2. We roepen login() aan uit AuthContext
3. AuthContext checkt of de credentials kloppen
4. Bij succes: AuthContext slaat de ingelogde user op (in state + localStorage)
5. Gebruiker wordt doorgestuurd naar dashboard
Maak een nieuw bestand: src/pages/Login.jsx
import { useState, useContext } from "react";
import { useNavigate } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";
function Login() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const { login } = useContext(AuthContext);
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
// Check of velden zijn ingevuld
if (!username || !password) {
setError("Vul alle velden in!");
return;
}
// Roep login functie aan uit AuthContext
const result = login(username, password);
if (result.success) {
// Succes! Ga naar dashboard
navigate("/dashboard");
} else {
// Er ging iets mis
setError(result.message); // "Verkeerde username of password!"
}
};
return (
<div className="auth-container">
<h1>Inloggen</h1>
<form onSubmit={handleSubmit}>
<div>
<label>Username:</label>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div>
<label>Password:</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
{error && <p className="error">{error}</p>}
<button type="submit">Inloggen</button>
</form>
<p>
Nog geen account? <a href="/register">Registreer hier</a>
</p>
</div>
);
}
export default Login;
De magie gebeurt hier!
We gebruiken login() uit de AuthContext. Deze functie doet alles: checkt de credentials, logt de user in, en slaat het op in localStorage. Nu weet de hele app dat deze user is ingelogd!
Hoe werkt het?
- User vult username + password in
- We roepen
login(username, password)aan - AuthContext checkt in localStorage["users"] of dit account bestaat
- Als het klopt: AuthContext zet user in state en localStorage["user"]
- We krijgen
{ success: true, message: "Ingelogd!" }terug - We navigeren naar dashboard
- Nu blijft de user ingelogd, zelfs na refresh!
Simpele Validatie
Je kunt makkelijk extra checks toevoegen:
1. Minimale Password Lengte
const handleSubmit = (e) => {
e.preventDefault();
if (password.length < 6) {
setError("Password moet minimaal 6 karakters zijn!");
return;
}
// Roep register/login aan...
};
2. Email Check (optioneel)
const handleSubmit = (e) => {
e.preventDefault();
if (!username.includes("@")) {
setError("Gebruik een geldig email adres!");
return;
}
// Roep register/login aan...
};
3. Password Match (voor register)
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (password !== confirmPassword) {
setError("Passwords komen niet overeen!");
return;
}
// Roep register aan...
};
Tip: Laat de error message verdwijnen als de user weer begint te typen:
onChange={(e) => {
setUsername(e.target.value);
setError(""); // Error verdwijnt
}}
Styling Tips
Voeg wat basis CSS toe om het er professioneel uit te laten zien:
/* src/index.css */
.auth-container {
max-width: 400px;
margin: 50px auto;
padding: 30px;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.auth-container h1 {
text-align: center;
margin-bottom: 30px;
}
.auth-container form div {
margin-bottom: 20px;
}
.auth-container label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.auth-container input {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.auth-container button {
width: 100%;
padding: 12px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
}
.auth-container button:hover {
background: #0056b3;
}
.auth-container .error {
color: red;
margin: 10px 0;
text-align: center;
}
.auth-container p {
text-align: center;
margin-top: 20px;
}
.auth-container a {
color: #007bff;
text-decoration: none;
}
.auth-container a:hover {
text-decoration: underline;
}
Vergeet Routes Niet!
Voeg de routes toe in je App.jsx:
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { AuthProvider } from "./context/AuthContext";
import Home from "./pages/Home";
import Register from "./pages/Register";
import Login from "./pages/Login";
import Dashboard from "./pages/Dashboard";
function App() {
return (
<AuthProvider>
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/register" element={<Register />} />
<Route path="/login" element={<Login />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
</BrowserRouter>
</AuthProvider>
);
}
Test de Complete Flow!
Volg deze stappen om te testen of alles werkt:
Eerste Keer - Registreren
- Start je app met
npm run dev - Ga naar
localhost:5173/register - Vul een username in (bijvoorbeeld: "jan")
- Vul een password in (bijvoorbeeld: "test123")
- Klik op "Registreren"
- Je ziet een alert: "Account aangemaakt!"
- Je wordt automatisch doorgestuurd naar
/login
Inloggen
- Op de login pagina, vul dezelfde username en password in
- Klik op "Inloggen"
- Je wordt doorgestuurd naar
/dashboard - Je ziet: "Welkom, jan!" op het dashboard
Check localStorage
- Open Chrome DevTools (F12)
- Ga naar tab "Application"
- Klik links op "Local Storage" → "http://localhost:5173"
- Je ziet nu 2 items:
users- array met alle geregistreerde accountsuser- de huidige ingelogde gebruiker
Test Persistentie
- Refresh de pagina (F5)
- Je bent nog steeds ingelogd!
- De username staat nog steeds in het dashboard
Het werkt! Je hebt nu een compleet registratie en login systeem:
- Nieuwe users kunnen een account aanmaken via
register() - Users kunnen inloggen via
login() - Alle auth logica staat in AuthContext (consistent!)
- Login blijft werken na refresh (dankzij localStorage)
- AuthContext zorgt dat alle componenten weten wie ingelogd is
Tip voor testen:
Wil je opnieuw testen? Clear localStorage:
DevTools → Application → Local Storage → Rechtermuisklik → Clear
Volgende Stap
Nu gaan we routes beveiligen zodat alleen ingelogde users bij bepaalde pagina's kunnen!
VolgendeProtected Routes
Beveilig routes zodat alleen ingelogde users toegang hebben