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?

  1. Bij opstarten: check of er een user in localStorage["user"] staat
  2. Bij login: zet user in state → useEffect slaat op in localStorage["user"]
  3. Bij logout: zet user op null → useEffect verwijdert uit localStorage["user"]
  4. 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!

Volgende

Login & Register Pages

Bouw formulieren die de register() en login() functies gebruiken