Wat Gaan We Maken?
We bouwen een AuthContext die bijhoudt:
- Is er iemand ingelogd?
- Wie is ingelogd? (gebruikersinfo)
- Register functie (account aanmaken)
- Login functie (inloggen)
- Logout functie (uitloggen)
- Blijft werken na refresh (met localStorage)
Het plan:
We maken 1 bestand (AuthContext.jsx) waar ALLE authentication logica in zit. Daarna kunnen we dit overal in onze app gebruiken!
Waarom register in AuthContext?
We zetten de register() functie in AuthContext zodat:
- Alle auth logica op 1 plek staat (register, login, logout)
- Het consistent is - alles via AuthContext
- We de logica niet hoeven te dupliceren
- Studenten makkelijker begrijpen waar auth code hoort
Stap 1: Context Aanmaken
Maak een nieuw bestand: src/context/AuthContext.jsx
import { createContext } from "react";
// Maak de Context (de doos voor login data)
export const AuthContext = createContext();
Let op: We exporteren direct met export (niet export default). Dit maakt importeren later makkelijker!
Stap 2: AuthProvider Component
Nu maken we een AuthProvider component. Deze houdt de login state bij en heeft de register/login/logout functies.
import { createContext, useState } from "react";
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
// State: is er iemand ingelogd?
const [user, setUser] = useState(null);
// Register functie - account aanmaken
const register = (username, password) => {
// Haal bestaande users op uit localStorage
const users = JSON.parse(localStorage.getItem("users") || "[]");
// Check of username al bestaat
const userExists = users.find(u => u.username === username);
if (userExists) {
return { success: false, message: "Username bestaat al!" };
}
// Voeg nieuwe user toe aan array
const newUser = { username, password };
users.push(newUser);
localStorage.setItem("users", JSON.stringify(users));
console.log("Account aangemaakt:", username);
return { success: true, message: "Account aangemaakt!" };
};
// Login functie - inloggen met bestaand account
const login = (username, password) => {
// Haal users op uit localStorage
const users = JSON.parse(localStorage.getItem("users") || "[]");
// Check of user bestaat met deze username + password
const foundUser = users.find(
u => u.username === username && u.password === password
);
if (!foundUser) {
return { success: false, message: "Verkeerde username of password!" };
}
// Zet user in state (zonder password voor veiligheid!)
setUser({ username: foundUser.username });
console.log("Ingelogd als:", foundUser.username);
return { success: true, message: "Ingelogd!" };
};
// Logout functie - uitloggen
const logout = () => {
setUser(null);
console.log("Uitgelogd");
};
return (
<AuthContext.Provider value={{ user, register, login, logout }}>
{children}
</AuthContext.Provider>
);
};
Uitleg van de functies:
• user = de ingelogde gebruiker (null = niet ingelogd)
• register() = maak nieuw account aan en sla op in localStorage["users"]
• login() = check credentials en log in
• logout() = zet user terug naar null
• {children} = alle componenten die binnen de Provider zitten
Waarom return { success, message }?
De register() en login() functies returnen een object:
{ success: true/false, message: "..." }
Zo kunnen de Register en Login pagina's makkelijk:
- Checken of het gelukt is (
success) - De gebruiker feedback geven (
message)
Wat is value?
In value zetten we ALLES wat we willen delen:
value={{ user, register, login, logout }}
Nu kan elk component deze 4 dingen gebruiken!
2 localStorage items
Let op: we gebruiken 2 verschillende localStorage items:
localStorage["users"]= array met ALLE accounts (voor register/login check)localStorage["user"]= de HUIDIGE ingelogde user (komt in stap 3!)
Stap 3: localStorage Toevoegen
Nu werkt register en login wel, maar als je de pagina refresht ben je uitgelogd!
Oplossing: sla de ingelogde user op in localStorage.
import { createContext, useState, useEffect } from "react";
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
// State: haal uit localStorage als er een user is opgeslagen
const [user, setUser] = useState(() => {
const savedUser = localStorage.getItem("user");
return savedUser ? JSON.parse(savedUser) : null;
});
// Sla user op in localStorage bij elke verandering
useEffect(() => {
if (user) {
localStorage.setItem("user", JSON.stringify(user));
} else {
localStorage.removeItem("user");
}
}, [user]);
// Register functie
const register = (username, password) => {
const users = JSON.parse(localStorage.getItem("users") || "[]");
const userExists = users.find(u => u.username === username);
if (userExists) {
return { success: false, message: "Username bestaat al!" };
}
const newUser = { username, password };
users.push(newUser);
localStorage.setItem("users", JSON.stringify(users));
console.log("Account aangemaakt:", username);
return { success: true, message: "Account aangemaakt!" };
};
// Login functie
const login = (username, password) => {
const users = JSON.parse(localStorage.getItem("users") || "[]");
const foundUser = users.find(
u => u.username === username && u.password === password
);
if (!foundUser) {
return { success: false, message: "Verkeerde username of password!" };
}
setUser({ username: foundUser.username });
console.log("Ingelogd als:", foundUser.username);
return { success: true, message: "Ingelogd!" };
};
// Logout functie
const logout = () => {
setUser(null);
console.log("Uitgelogd");
};
return (
<AuthContext.Provider value={{ user, register, login, logout }}>
{children}
</AuthContext.Provider>
);
};
Nu blijft de login werken na refresh!
De ingelogde user wordt opgeslagen in localStorage["user"] en weer terug gehaald als je terugkomt.
Hoe werkt dit?
- Bij opstarten: check of er een user in localStorage["user"] staat
- Bij login: zet user in state → useEffect slaat op in localStorage["user"]
- Bij logout: zet user op null → useEffect verwijdert uit localStorage["user"]
- Bij refresh: haal user weer op uit localStorage["user"]
De 2 localStorage items uitgelegd
We hebben nu 2 verschillende items in localStorage:
localStorage["users"] - ALLE accounts
Voorbeeld: [{ username: "jan", password: "test123" }, { username: "lisa", password: "abc" }]
Dit is een array met alle geregistreerde accounts. Wordt gebruikt bij register (toevoegen) en login (checken).
localStorage["user"] - HUIDIGE ingelogde user
Voorbeeld: { username: "jan" }
Dit is een enkel object met de ingelogde gebruiker. Wordt gebruikt om na refresh weer in te loggen.
Stap 4: AuthProvider in App.jsx
Nu moeten we de AuthProvider om onze hele app heen zetten.
// src/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>
);
}
export default App;
Let op de volgorde!
AuthProvider → BrowserRouter → Routes
Zo kunnen alle routes bij de auth functies!
AuthContext Gebruiken
Nu kunnen we in ELK component de auth functies gebruiken met useContext!
Voorbeeld 1: Register Gebruiken
import { useContext, useState } 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();
// Roep register aan uit AuthContext
const result = register(username, password);
if (result.success) {
alert(result.message); // "Account aangemaakt!"
navigate("/login");
} else {
setError(result.message); // "Username bestaat al!"
}
};
// ... rest van component
}
Voorbeeld 2: Login Gebruiken
import { useContext, useState } 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();
// Roep login aan uit AuthContext
const result = login(username, password);
if (result.success) {
navigate("/dashboard");
} else {
setError(result.message); // "Verkeerde username of password!"
}
};
// ... rest van component
}
Voorbeeld 3: User Tonen
import { useContext } from "react";
import { AuthContext } from "../context/AuthContext";
function Header() {
const { user } = useContext(AuthContext);
return (
<header>
{user ? (
<p>Welkom, {user.username}!</p>
) : (
<p>Niet ingelogd</p>
)}
</header>
);
}
Voorbeeld 4: Logout Button
import { useContext } from "react";
import { useNavigate } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";
function LogoutButton() {
const { logout } = useContext(AuthContext);
const navigate = useNavigate();
const handleLogout = () => {
logout();
navigate("/");
};
return (
<button onClick={handleLogout}>
Uitloggen
</button>
);
}
Zo simpel is het!
• Gebruik register() in je register form
• Gebruik login() in je login form
• Gebruik user om te checken of iemand ingelogd is
• Gebruik logout() in je logout button
Complete Code
Dit is de complete AuthContext.jsx die je kunt copy-pasten:
// src/context/AuthContext.jsx
import { createContext, useState, useEffect } from "react";
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
// State: haal uit localStorage als er een user is opgeslagen
const [user, setUser] = useState(() => {
const savedUser = localStorage.getItem("user");
return savedUser ? JSON.parse(savedUser) : null;
});
// Sla user op in localStorage bij elke verandering
useEffect(() => {
if (user) {
localStorage.setItem("user", JSON.stringify(user));
} else {
localStorage.removeItem("user");
}
}, [user]);
// Register functie
const register = (username, password) => {
const users = JSON.parse(localStorage.getItem("users") || "[]");
const userExists = users.find(u => u.username === username);
if (userExists) {
return { success: false, message: "Username bestaat al!" };
}
const newUser = { username, password };
users.push(newUser);
localStorage.setItem("users", JSON.stringify(users));
console.log("Account aangemaakt:", username);
return { success: true, message: "Account aangemaakt!" };
};
// Login functie
const login = (username, password) => {
const users = JSON.parse(localStorage.getItem("users") || "[]");
const foundUser = users.find(
u => u.username === username && u.password === password
);
if (!foundUser) {
return { success: false, message: "Verkeerde username of password!" };
}
setUser({ username: foundUser.username });
console.log("Ingelogd als:", foundUser.username);
return { success: true, message: "Ingelogd!" };
};
// Logout functie
const logout = () => {
setUser(null);
console.log("Uitgelogd");
};
return (
<AuthContext.Provider value={{ user, register, login, logout }}>
{children}
</AuthContext.Provider>
);
};
Volgende Stap
Nu je AuthContext hebt met register en login functies, gaan we de pagina's maken die deze functies gebruiken!
VolgendeLogin & Register Pages
Bouw formulieren die de register() en login() functies gebruiken