React Basics

Opwarmoefening

Facebook likes

  • Toon in de browser wie een bericht leuk vindt op basis van een array namen. Bij elke klik wordt een nieuwe naam toegevoegd en moet de UI handmatig geüpdatet worden.
<div id="likes">
  <span class="icon">❤️</span>
  <span id="likes-text"></span>
</div>

<button id="add">Add like</button>

index.html

Opwarmoefening

Vereisten:

  • Schrijf een functie likes(names) die een array van namen ontvangt

  • De functie retourneert een correcte tekst a.d.h.v length zoals:

    • No one likes this

    • Peter likes this

    • Peter and Sarah like this

    • Peter, Sarah and 2 others like this.

Opwarmoefening

Vereisten:

  • Toon deze tekst in de browser

  • Wanneer je op “Add like” klikt:

    • wordt een willekeurige naam toegevoegd aan de array

    • wordt de UI manueel opnieuw gerenderd met een functie render()

Opwarmoefening

Resultaat:

React

Achtergrond

Waarom React?

  • Plain vanilla Javascript heeft een aantal nadelen
    • Veel manuele DOM-manipulatie

    • Moeilijk schaalbaar bij groeiende applicaties

    • Kans op fouten wanneer data en UI niet in sync zijn

    • ...

 Dit hebben we net (kleinschalig) ervaren in de likes-oefening.

  • Plain vanilla Javascript heeft een aantal nadelen
    • Veel manuele DOM-manipulatie

    • Moeilijk schaalbaar bij groeiende applicaties

    • Kans op fouten wanneer data en UI niet in sync zijn

    • ...

Waarom React?

Imperatief programmeren

Beschrijven hoe iets moet gebeuren.

element.innerText = text;
element.classList.add("active");
  • Jij beslist wanneer en hoe de UI verandert

  • Meer controle, maar ook meer verantwoordelijkheid

Waarom React?

Declaratief programmeren

Beschrijven wat het eindresultaat moet zijn

<p className="active">{text}</p>
  • React regelt de updates

  • Minder kans op fouten

  • Code is makkelijker te begrijpen

Waarom React?

Waarom werkt plain JavaScript niet goed op schaal?

  • Veel getElementById / querySelector

  • Meerdere render()-functies

  • Data wordt op meerdere plaatsen gebruikt

  • Kleine wijziging → veel code aanpassen

“Dit werkt voor kleine voorbeelden, maar niet voor echte apps.”

Waarom React?

Het antwoord: Component based frameworks

React, Angular, Vue, ... werken met componenten:

  • Kleine, herbruikbare stukken UI

  • Elk component heeft:

    • eigen structuur

    • eigen logica

    • eigen data

App
 ├── Likes
 ├── Button
 └── Counter

Waarom React?

Voordelen van component based & declaratief werken

  • Leesbaar

  • Testbaar

  • Herbruikbaar

  • Onderhoudbaar

  • Makkelijk uitbreidbaar

Waarom React?

Waarom kiezen wij voor React?

  • Zeer populair in de industrie

  • Grote community

  • Veel jobs

  • Werkt samen met TypeScript

  • Enkel focussen op UI (library, geen framework)

React laat ons UI bouwen op een manier die leesbaar, voorspelbaar en schaalbaar is.

React

Start a project

Start a project

  • We gebruiken een tool die alles voor ons klaarzet. (vite)
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev

Start a project

  • Vite zet voor ons bepaalde zaken klaar zoals:
    • Ontwikkelserver

    • Build configuratie

    • Moderne JavaScript setup

    • Live reload

Zonder deze tool zou dat veel werk zijn

Start a project

  • Je krijgt heel wat files maar de belangrijkste files zijn:
my-react-app/
 ├── node_modules/
 ├── public/
 ├── src/
 │    ├── App.tsx
 │    └── main.tsx
 ├── index.html
 └── package.json

Start a project

De belangrijkste files voorlopig zijn main.tsx en App.tsx

 ├── src/
 │    ├── App.tsx
 │    └── main.tsx

main.tsx

  • Startpunt van de applicatie

  • Verbindt React met de HTML

  • Hier werken we bijna nooit

App.tsx

  • Hoofdcomponent van onze applicatie

  • Hier bouwen we onze UI

  • Dit is waar alles samenkomt.

Start a project

Hoe bouwen we een UI in react?

  • We maken components

  • Components zijn JavaScript-functies

  • Components geven JSX terug

  • Components kunnen data ontvangen (props)

Tip: Het bestand eindigt op TSX bij ons omdat wij typescript gebruiken. Zonder typescript is het javascript dus JSX

React

Likes oefening (React)

Likes oefening

We bouwen de Facebook likes opnieuw,
maar nu in React, zonder DOM-manipulatie.

➡️ Logica blijft hetzelfde.

Likes oefening

Plak de likes function uit opwarmoefening in App.tsx

function likes(names) {
  if (names.length === 0) return "No one likes this";
  if (names.length === 1) return `${names[0]} likes this`;
  if (names.length === 2) return `${names[0]} and ${names[1]} like this`;
  if (names.length === 3)
    return `${names[0]}, ${names[1]} and ${names[2]} like this`;

  return `${names[0]}, ${names[1]} and ${names.length - 2} others like this`;
}

Likes oefening

Nu pakken we de rendering aan van onze App.

function App() {
  const names = [];

  return (
    <div className="card">
      <div className="likes">
        <span className="icon">❤️</span>
        <span>{likes(names)}</span>
      </div>
    </div>
  );
}

 

  • Geen getElementById

  • Geen innerText

  • Geen render()

 

Likes oefening

text.innerText = likes(names);

 

  • In React beschrijven we wat er moet staan

  • React zorgt voor de DOM

 

Vanilla javascript

React

<span>{likes(names)}</span>

Likes oefening

<span class="icon">❤️</span>

 

  • JSX: syntax om HTML en Javascript te combineren

    • ​Indien TypeScript → TSX

  • ​Kan niet om met gereserveerde woorden in JS/TS
    bv. class (→ className), for (→ htmlFor), ...

     

Vanilla javascript

React

<span className="icon">❤️</span>

Likes oefening

 

  • Waarom niet?

  • Wat missen we?

We zien nu wel onze UI maar niets is interactief.

Likes oefening

Wat React nu al voor ons oplost:

  • Geen DOM-manipulatie

  • Duidelijke link tussen data en UI

  • Leesbare code

  • Minder kans op fouten

Wat nog niet?

  • Dynamische data

  • Interactie

Conventies

  • Naam van de component:
    start met een hoofdletter (App, Button ...)

  • Componenten exporteer je als een functie

    • export default function App() { ... }
  • In de curly braces ({}) kan je JavaScript schrijven

React

JSX

JSX

Goed om weten:

  • JSX wordt door React omgevormd naar JavaScript tijdens het builden van je applicatie
  • Error? Bekijk de output van je terminal-applicatie.

The rules of JSX

3 regels voor het gebruik van JSX:

  1. Geef altijd maximaal 1 HTML-element terug of
    gebruik een fragment (<>)
  2. Sluit alle tags
  3. Gebruik (bijna) overal camelCase

React

useState

useState

function App() {
  let names = [];

  function addLike() {
    names.push("Peter");
  }

  return (
    <div>
      <button onClick={addLike}>Add like</button>
      <p>{likes(names)}</p>
    </div>
  );
}

Wat verwachten we? Wat gebeurt er?

 

We maken nu een addLike functie en plaatsen deze op de button in App.tsx

useState

React rendert componenten opnieuw bij verandering.
Variabelen worden dan opnieuw aangemaakt.

 

Wat is hier het probleem?

  • Gewone variabele in React
    • React onthoudt ze niet

    • Ze verdwijnen bij elke render

    • React weet niet dat ze veranderd zijn

useState

➡️ Dat is precies wat useState doet.

We hebben een manier nodig om:

  • data te onthouden tussen renders

  • React te verwittigen dat data werd gewijzigd

useState

useState is een React Hook die data bewaart
én React laat weten wanneer die data verandert.

Wat is een useState?

useState

import { useState } from "react";

function App() {
  const [names, setNames] = useState([]);

  return (
    <div>
      <p>{likes(names)}</p>
    </div>
  );
}
  • names → huidige waarde

  • setNames → enige manier om te wijzigen

  • useState([]) → startwaarde

useState

Aanpassen van een state

function addLike() {
  setNames([...names, "Peter"]);
}
  • Geen push

  • Nieuwe array maken

  • React ziet het verschil → re-render

useState

Gewone variabele useState
Wordt vergeten Blijft bestaan
Triggert geen render Triggert render
React weet niets  React weet alles

Waarom gebruiken we niet altijd een useState?

Try it yourself!

Oefening 1: Number state tonen

Maak een useState count met startwaarde 0
Toon de waarde in de UI.

Try it yourself!

Oefening 1: Number state tonen

  • Maak een state variabele count met startwaarde 0

  • Toon de waarde van count

  • Verhoog count met 1 wanneer je op de knop klikt

import { useState } from "react";

function App() {
  // TODO: maak een state variabele "count" met startwaarde 0

  return (
    <div>
      {/* TODO: toon de waarde van count */}
      <p>Count:</p>

      {/* TODO: verhoog count met 1 bij klik */}
      <button onClick={() => {}}>
        Increment
      </button>
    </div>
  );
}

export default App;

Try it yourself!

Oefening 2: Change Name

  • Maak een useState name met startwaarde "Peter"

  • Toon “Hello {name}”

  • Verander naar "Sarah" wanneer je op de knop klikt

function App() {
  // TODO: maak een state variabele "name" met startwaarde "Peter"

  return (
    <div>
      {/* TODO: toon de naam in de tekst */}
      <p>Hello</p>

      {/* TODO: verander de naam naar "Sarah" bij klik */}
      <button onClick={() => {}}>
        Change name
      </button>
    </div>
  );
}

export default App;

Try it yourself!

Oefening 3: Bool-Online

  • Maak een state isOnline met startwaarde true

  • Toon "Online" of "Offline"

  • Toggle de waarde bij klik

function App() {
  // TODO: maak een boolean state "isOnline" met startwaarde true

  return (
    <div>
      <p>
        Status: 
        {/* TODO: toon "Online" of "Offline" */}
      </p>

      {/* TODO: toggle isOnline bij klik */}
      <button onClick={() => {}}>
        Toggle status
      </button>
    </div>
  );
}

export default App;

React

Components (refactoring)

Component

Waarom splitsen we code op?

  • Veel JSX in één bestand

  • Moeilijk leesbaar

  • Moeilijk herbruikbaar

  • Alles hangt samen

Component

React component is:

  • Een JavaScript functie

  • Die JSX teruggeeft

  • En een stuk UI beschrijft

function MyComponent() {
  return <div>Hello</div>;
}

Component

In onze huidige app hebben we dit:

function App() {
  const [names, setNames] = useState([]);

  return (
    <div className="card">
      <button onClick={() => setNames([...names, "Peter"])}>
        Add like
      </button>

      <div className="likes">
        <span>❤️</span>
        <span>{likes(names)}</span>
      </div>
    </div>
  );
}

Zien jullie hier verschillende 'stukken' UI in?

Component

De UI bestaat uit:

  • Likes weergave

  • Actie (knop)

 

Card
 ├── Button
 └── Likes

Zien jullie hier verschillende 'stukken' UI in?

Component

Zo kunnen we een eerste component "Likes" maken.
Dit doen we vaak in een mapje "components".

function Likes({ names }) {
  return (
    <div className="likes">
      <span>❤️</span>
      <span>{likes(names)}</span>
    </div>
  );
}
  • names komt van buitenaf (Prop)

  • Component is stateless

  • Logica blijft herbruikbaar

components/Likes.tsx

Component

Deze component kunnen we makkelijk gebruiken in App.

import Likes from "./components/Likes";

function App() {
  const [names, setNames] = useState([]);

  return (
    <div className="card">
      <button onClick={() => setNames([...names, "Peter"])}>
        Add like
      </button>

      <Likes names={names} />
    </div>
  );
}

We hebben code opgesplitst zonder functionaliteit te verliezen

Props

Props = Data voor een component

  • Vergelijkbaar met functie-argumenten

  • Alleen-lezen

  • Van parent → child

<Likes names={names} />

Herbruikbaar met andere data!

<Likes names={names} />
<Likes names={["Peter"]} />
<Likes names={["Anna", "Lisa"]} />

Props

Wat hoort waar?

  • State → zo hoog mogelijk

  • UI → zo laag mogelijk

  • Logica → bij de component die ze gebruikt

Voordelen van components:

  • Leesbaardere code

  • Herbruikbare UI

  • Makkelijker testen

  • Makkelijker uitbreiden

Try it yourself!

Oefening 1: Circle component

  • Maak een component Circle

  • De component toont een gekleurde cirkel

  • Render de component in App.tsx

function Circle() {
  // TODO: return JSX die een cirkel toont
  return (
    
  );
}

Try it yourself!

Oefening 2: Badge component

  • Maak een component Badge

  • De component toont een label in een gekleurd vakje

  • Geef de tekst door via props

type BadgeProps = {
  // TODO: voeg een prop "text" toe
};

function Badge(props: BadgeProps) {
  return (
      {/* TODO: toon de tekst */}
  );
}

Try it yourself!

Oefening 3: ProfileCard component

  • Maak een component ProfileCard

  • Toon een naam en leeftijd

  • Geef beide waarden door via props

Geen Startercode?!
Probeer nu zelf code te schrijven zonder start

Try it yourself!

Oefening 4: StatusMessage component

  • Maak een component StatusMessage

  • Toon “Online” of “Offline”

  • Geef de status door via een boolean prop

React

Events

Interactie met components

Tot nu toe:

  • Data ging van parent → child

  • Maar UI bevat vaak knoppen en acties

Hoe laten we een component iets “doen”?

Events

Events in React:

  • React gebruikt camelCase

  • Events krijgen een functie

<button onClick={handleClick}>Click me</button>

Wat is anders met vanilla JS?

  • Geen strings
  • Geen getElement
  • Geen addEventListener

Events

We maken het voorbeeld met de LikeButton

function LikeButton() {
  return <button>Add like</button>;
}

Probleem:

  • Deze knop weet niets over names

  • Waar komt de logica?

Events

Oplossing: Functie doorgeven als prop

function LikeButton({ onLike }) {
  return <button onClick={onLike}>Add like</button>;
}

Component voert gedrag uit dat het krijgt.

 

 

 

Wij zullen vanuit App de functie meegeven aan de LikeButton die de veranderingen teweeg zullen brengen.

Events

De state blijft in onze App en we maken een functie aan om door te geven aan de LikeButton

function App() {
  const [names, setNames] = useState([]);

  function addLike() {
    setNames([...names, "Peter"]);
  }

  return (
    <div className="card">
      <LikeButton onLike={addLike} />
      <Likes names={names} />
    </div>
  );
}

 

  • State blijft bovenaan

  • Child triggert verandering

 

Events

Data flow in React

App (state)
 ↓ props
LikeButton      Likes
 ↑ events        ↑ props

 

  • Data gaat naar beneden
  • Events gaan naar boven

React

useEffect

useEffect

Tot nu toe:

  • We beschrijven UI

  • UI volgt uit state

  • Components zijn puur

Maar… wat als we iets willen doen naast renderen?

useEffect

Dit noement we een side effect.

Side effects zijn dingen die:

  • Niet puur UI zijn

  • Buiten React gebeuren

Voorbeelden:

  • console.log

  • document.title

  • API calls (later)

  • timers

useEffect

Hiervoor maken we gebruiken van een andere hook genaamd useEffect.

 useEffect laat je code uitvoeren na het renderen van een component. 

useEffect(() => {
  console.log("Rendered");
});

useEffect

Voorbeeld:

import { useEffect } from "react";

function App() {
  useEffect(() => {
    console.log("App rendered");
  });

  return <h1>Hello</h1>;
}
  • Wordt uitgevoerd na render

  • Kan meerdere keren lopen

useEffect

Dependencies zijn zaken die je kan meegeven aan de useEffect waarop die moet letten. (Array na de function)

useEffect(() => {
  console.log("Names changed");
}, [names]);
  • Effect loopt wanneer names verandert

  • React vergelijkt oude en nieuwe waarde

TIP: Wil je dat het maar 1 keer gebeurd? Geef dan een lege dependency array mee.

useEffect

Waar kunnen we dit gebruiken? Als we dit op onze likes oefening toepassen kan dit als volgt:

useEffect(() => {
  document.title = `${names.length} likes`;
}, [names]);

Nu zal de titel van het document aanpassen iedere keer als de array van names verandert.

useEffect

Wat is useEffect NIET?

  • vervanging van useState

  • render functie

  • event handler

➡️ useEffect = reactie op verandering

useEffect

Wanneer gebruiken we useEffect?

  • Je iets moet doen na render

  • Iets buiten React moet gebeuren

Gebruik het niet voor:

  • berekeningen

  • UI-logica

Try it yourself

Oefening 1: 

  • Gebruik useEffect

  • Log "Component rendered" in de console

  • Laat het effect lopen na elke render

import { useEffect } from "react";

function App() {
  // TODO: voeg een useEffect toe die iets logt in de console

  return (
    <div>
      <h1>Hello React</h1>
    </div>
  );
}

export default App;

Try it yourself

Oefening 2: 

  • Maak een state count

  • Verhoog count bij klik

  • Gebruik useEffect en log wanneer count verandert

function App() {
  // TODO: maak een state "count" met startwaarde 0

  // TODO: gebruik useEffect om iets te loggen wanneer count verandert

  return (
    <div>
      {/* TODO: toon count */}
      <p>Count:</p>

      {/* TODO: verhoog count bij klik */}
      <button onClick={() => {}}>
        Increment
      </button>
    </div>
  );
}

export default App;

Try it yourself

Oefening 3: 

  • Maak een state likes

  • Gebruik useEffect om de pagina-titel aan te passen

function App() {
  // TODO: maak een state "likes" met startwaarde 0

  // TODO: gebruik useEffect om document.title aan te passen
  // Tip: gebruik likes in de dependency array

  return (
    <div>
      {/* TODO: toon likes */}
      <p>Likes:</p>

      {/* TODO: verhoog likes bij klik */}
      <button onClick={() => {}}>
        Add like
      </button>
    </div>
  );
}

export default App;

React

Oefeningen

Oefeningen

Oefening 1 - Emoji Counter

  • Maak een component EmojiCounter die een emoji en een teller toont

  • Klikken op de knop verhoogt de teller

  • Log in useEffect telkens als de teller verandert

Oefeningen

Oefening 2 - Tamagochi

  • Component PetCard met props name

  • Houd interne states bij: hunger en happiness

  • Knoppen: “Feed” en “Play”

  • useEffect logt als hunger > 5 (“Pet is hungry!”)

Oefeningen

Oefening 3 - Countdown Timer

  • Component TimerDisplay toont timeLeft

  • In App: start timer bij klik, tel af van 10 naar 0

  • useEffect zorgt dat timer telt

Oefeningen

Oefening 4 - Mood Tracker

  • Component Mood met prop emoji

  • In App: state currentMood met startwaarde "😊"

  • Knoppen in App: "😊" en "😢" → verandert state

  • useEffect logt "Mood changed: {currentMood}"

Oefeningen

Oefening 5 - Click Me Counter

  • Component ClickDisplay met prop count → toont "Clicked {count} times"

  • In App: state clickCount start op 0

  • Knop “Click me” → verhoogt clickCount

  • useEffect logt "Clicked: {clickCount}"

PGM3/2 - React Basics

By Lecturer GDM

PGM3/2 - React Basics

  • 35