fix: les 6

This commit is contained in:
2026-03-11 14:07:00 +01:00
parent d5066021ab
commit 9ffdecf2c4
117 changed files with 13198 additions and 5194 deletions

View File

@@ -1,234 +1,58 @@
# Les 5: TypeScript voor React
# Les 5: Next.js — Het React Framework (Part 1)
---
## Hoofdstuk
**Deel 2: Technical Foundations** (Les 4-9)
**Deel 2: Technical Foundations** (Les 4-8)
## Beschrijving
Verdieping in TypeScript met focus op React-patronen. Studenten leren generics, utility types, en hoe je React components, hooks, events en API calls correct typt. Voorbereiding op Les 6 waar ze met Next.js aan de slag gaan.
**Voorkennis:** Les 4 (TypeScript Fundamentals) — basic types, interfaces, union types, type aliases, functies typen.
Introductie Next.js voor React developers. App Router, routing, server/client components, data fetching. Hands-on: QuickPoll app Part 1 (stap 0-3) klassikaal bouwen.
---
## Te Behandelen
## Te Behandelen (~45 min theorie)
### Generics (20 min)
- Waarom generics? Herbruikbare, type-safe code
- `Array<T>`, `Promise<T>` — generics die ze al kennen
- Eigen generics schrijven: `function getFirst<T>(items: T[]): T`
- Generics met constraints: `<T extends { id: string }>`
- `keyof` operator: `function getValue<T, K extends keyof T>(obj: T, key: K): T[K]`
```typescript
// Generic functie
function wrapInArray<T>(value: T): T[] {
return [value];
}
wrapInArray("hello"); // string[]
wrapInArray(42); // number[]
// Met constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
```
- Waarom Next.js? React is een library, Next.js is het framework
- Create-next-app setup met TypeScript + Tailwind
- App Router: folder-based routing (page.tsx = route)
- Layouts: root layout, nested layouts
- Dynamic Routes: [id] met Promise-based params (Next.js 15)
- Server Components vs Client Components
- "use client" directive
- Data Fetching in async Server Components
- Server Actions introductie ("use server")
- Route Groups ((marketing))
- Project structuur best practices
---
### Utility Types (15 min)
- `Partial<T>` — alle properties optioneel (handig voor updates)
- `Pick<T, K>` — selecteer specifieke properties
- `Omit<T, K>` — alles behalve specifieke properties
- `Record<K, V>` — key-value mapping
- Praktisch voorbeeld: `updateUser(id: string, data: Partial<User>)`
## Lesopdracht (120 min, klassikaal)
```typescript
interface User {
id: string;
name: string;
email: string;
age: number;
}
### QuickPoll App Part 1 — samen met Tim
// Partial: voor update functies
function updateUser(id: string, updates: Partial<User>): User { ... }
updateUser("1", { name: "Tim" }); // alleen name updaten
- **Stap 0:** Setup (create-next-app, npm install, dev server)
- **Stap 1:** Layout met navigatie (Tailwind styling)
- **Stap 2:** Homepage met polls lijst (server component)
- **Stap 3:** API route GET single poll (dynamic route, 404 handling)
// Omit: voor create functies (id wordt server-side gegenereerd)
type CreateUserInput = Omit<User, "id">;
// Pick: voor specifieke views
type UserPreview = Pick<User, "id" | "name">;
```
---
### React Props Typen (20 min)
- Interface voor component props
- Children typen met `React.ReactNode`
- Callback props: `onClick: () => void`, `onChange: (value: string) => void`
- Spread props en prop forwarding
- Default values met destructuring
```typescript
interface CardProps {
title: string;
children: React.ReactNode;
variant?: "default" | "highlighted";
onClose?: () => void;
}
function Card({ title, children, variant = "default", onClose }: CardProps) {
return (
<div className={`card card-${variant}`}>
<h2>{title}</h2>
{onClose && <button onClick={onClose}>×</button>}
{children}
</div>
);
}
```
---
### useState & useEffect Typen (15 min)
- Type inference bij useState: `useState(0)` → number
- Explicit types: `useState<User | null>(null)`
- Arrays: `useState<Product[]>([])`
- useEffect met async patterns
```typescript
const [user, setUser] = useState<User | null>(null);
const [products, setProducts] = useState<Product[]>([]);
const [loading, setLoading] = useState(false); // inference: boolean
useEffect(() => {
async function fetchData() {
setLoading(true);
const response = await fetch("/api/users");
const data: User[] = await response.json();
setUsers(data);
setLoading(false);
}
fetchData();
}, []);
```
---
### Event Handlers Typen (10 min)
- `React.ChangeEvent<HTMLInputElement>`
- `React.FormEvent<HTMLFormElement>`
- `React.MouseEvent<HTMLButtonElement>`
- Tip: hover in Cursor om het juiste event type te vinden
```typescript
function SearchForm() {
const [query, setQuery] = useState("");
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setQuery(e.target.value);
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Searching:", query);
};
return (
<form onSubmit={handleSubmit}>
<input value={query} onChange={handleChange} />
</form>
);
}
```
---
### API Responses & Async Typen (15 min)
- `Promise<T>` voor async functies
- API response types definiëren
- Error handling met types
- Fetch wrapper met generics
```typescript
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
async function fetchApi<T>(url: string): Promise<ApiResponse<T>> {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
}
// Gebruik
const { data: users } = await fetchApi<User[]>("/api/users");
const { data: product } = await fetchApi<Product>("/api/products/1");
```
Huiswerk: Stap 0-3 zelfstandig afmaken
---
## Tools
- Cursor (Student Plan)
- Next.js 15
- Cursor
- TypeScript
- React (via CDN of Vite)
---
## Lesopdracht (75 min)
### Typed React Dashboard
Studenten bouwen een kleine React-app met volledig getypte components:
**Opdracht:** Bouw een Product Dashboard met:
1. **`ProductCard` component** — props: Product interface, onAddToCart callback
2. **`ProductList` component** — props: Product[], filterCategory (union type)
3. **`SearchBar` component** — props: query string, onChange handler (getypt event)
4. **`useProducts` custom hook** — fetch products, return `{ products, loading, error }`
5. **Alle types in een apart `types.ts` bestand**
**Vereisten:**
- Geen `any` toegestaan
- Alle event handlers correct getypt
- useState met expliciete types waar nodig
- Minstens 1 generic functie (bijv. een `sortBy<T>` of `filterBy<T>`)
---
## Huiswerk (2 uur)
### Extend het Dashboard
Bouw voort op de lesopdracht:
1. **Shopping Cart** toevoegen met getypte state (`CartItem[]`)
2. **API simulatie** — maak een `fetchProducts()` functie met `Promise<Product[]>`
3. **Utility types gebruiken**`Partial<Product>` voor updates, `Omit<Product, "id">` voor create
4. **Bonus: Generic `DataTable<T>` component** — werkt met elke array van objecten
### Deliverable
- Werkend React project met TypeScript
- Alle components volledig getypt
- `npm run check` = 0 errors
- Tailwind CSS
---
## Leerdoelen
Na deze les kan de student:
- Generics schrijven en toepassen
- Utility types gebruiken (Partial, Pick, Omit, Record)
- React component props correct typen
- useState en useEffect met types gebruiken
- Event handlers typen (ChangeEvent, FormEvent, MouseEvent)
- Async functies en API responses typen met Promise<T>
- Een custom hook schrijven met correcte return types
- Uitleggen wat Next.js toevoegt aan React
- Een Next.js project opzetten met App Router
- Verschil tussen Server en Client Components
- File-based routing gebruiken
- Dynamic routes met parameters maken
- Data fetchen in Server Components