TECH3

EAT, SLEEP, REACT ... REPEAT​​

03                                        2025-2026

In dit onderdeel herhalen we de basisprincipes van React, zodat we vertrouwd raken met de belangrijkste concepten. Dit om nadien aan de slag te kunnen gaan met React Three fiber.

EAT, SLEEP, REACT ... REPEAT

SETUP

01

01

SETUP

SETUP

Hoe zetten we een React App op? 

Voer volgende uit in de terminal 

npm create vite@latest

Volg deze stappen:

  • Kies een naam voor het project
  • Selecteer een framework (REACT)
  • Selecteer Typescript + Compiler
  • 'No' to rolldown-vite (experimental)
  • Install with npm and start (yes)

 

01

SETUP

WHY?

We maken gebruik van React en React Three Fiber omdat het ons leven makkelijk zal maken. Je kan vanilla javascript gebruiken met three.js maar dit is veel handmatig werk terwijl React Three Fiber dit voor ons al doet.

EAT, SLEEP, REACT ... REPEAT

COMPONENTS

02

02

COMPONENTS

COMPONENTS

Components zijn herbruikbare bouwblokken van je applicatie.

  • Overzicht te bewaren 
  • Herbruikbaarheid (bv. Button)
  • Seperation of Concerns (1 component heeft 1 taak)
  • Onderhoudbaarheid (Je weet direct waar de fout ligt of kan makkelijk aanpassingen maken zonder de hele applicatie kapot te maken)
  • State management (components kunnen hun eigen state beheren waardoor je makkelijk interactieve UI's kan bouwen)
  • Consistentie
  • ...

 

 

02

COMPONENTS

BASIC COMPONENTS

We maken een basic 'functional' component aan die we nadien in App gebruiken. (components/Hello/Hello.tsx)

const Hello: React.FC = () => {
  return (
        <h1>Hello</h1>
  )
}

export default Hello

Wanneer we nu een paragraph willen toevoegen hieraan werkt dit niet.

 return (
        <h1>Hello</h1>
        <p>This is a simple React component.</p>
  )

Hoe kunnen we dit wel doen laten werken?

02

COMPONENTS

FRAGMENT

Door gebruik te maken van een fragment kunnen we meerdere elementen plaatsen in een component. 

const Hello: React.FC = () => {
  return (
    <>
        <h1>Hello</h1>
        <p>This is a simple React component.</p>
    </>
  )
}

export default Hello

Een fragment (<> </>) kan je beschouwen als een onzichtbare 'div'. Je zou ook een div kunnen plaatsen in de plaats maar die wordt dan wel in je HTML gerendered, een fragment niet.

02

COMPONENTS

CALL IT

Nu we een simpele component hebben aangemaakt is het tijd om deze in de App aan te roepen.

import Hello from './components/Hello/Hello'

function App() {

  return (
    <>
      <Hello />
    </>
  )
}

export default App

We kunnen zo ook een hele structuur opbouwen van components in components om overzicht te bewaren. Je kiest hier zelf in hoe ver je gaat blijf consistent. (bv. Hero component met daarin andere mini-components)

02

COMPONENTS

PROPS

Het zou handig zijn om iets mee te kunnen geven aan een component.
Dit doen we met props.

import Hello from './components/Hello/Hello'

function App() {

  return (
    <>
      <Hello name={"Niels"}/>
    </>
  )
}

export default App

in App.tsx

02

COMPONENTS

PROPS

interface HelloProps {
    name: string;
}

const Hello: React.FC<HelloProps> = ({name}) => {

  return (
    <>
        <h1>Hello {name}</h1>
        <p>This is a simple React component.</p>
    </>
  )
}

export default Hello

Vervolgens in Hello.tsx destructure je de prop en maak je een interface/type aan.

  • Props = data van parent naar child

  • TypeScript interface/type geeft typeveiligheid

EAT, SLEEP, REACT ... REPEAT

USESTATE()

03

03

USESTATE()

WHAT IS IT?

useState is een hook die componenten toestaat om interne data bij te houden.

  • useState() is een React Hook voor component state.

  • Laat een component interne data onthouden tussen renders.

  • Component wordt automatisch opnieuw gerenderd als de state verandert.

  • TypeScript helpt bij het definiëren van de juiste type van de state.

  • Staat toe dat je component interactief wordt (bijv. buttons, toggles, inputs).

  • Vaak gecombineerd met events zoals onClick of onChange.

  • Basisvoorwaarde voor reactieve UI, essentieel voor dynamische interfaces zoals in Three Fiber.

03

USESTATE()

CLICK IT!

We zullen dit concept uitleggen aan de hand van een clicker component.

Maak een clicker component aan in components/Clicker/Clicker.tsx

import React from 'react'

const Clicker: React.FC = () => {
  return (
    <div>
        Clicker
    </div>
  )
}

export default Clicker

Deze component doet nu nog zeer weinig maar we bouwen dit stap voor stap op.

Roep deze aan in App.tsx

<>
   <Clicker />
</>

03

USESTATE()

CLICK IT!

We passen de layout aan zodat we een tekst hebben met een button.

Verander de code naar volgende in Clicker.tsx

const Clicker: React.FC = () => {
  return (
    <>
    <div>Click count: 0</div>
    <button>Click me</button>
    </>
  )
}

De button werkt nu nog niet en de click count blijft op 0 staan. We moeten nu gebruik maken van Hooks en Events.

03

USESTATE()

CLICK IT!

Eerst zien we hoe het NIET moet om hieruit te leren.

We maken een count variabele aan in de clicker component.

import React from 'react'

const Clicker: React.FC = () => {

  const count = 0;

  return (
    <>
    <div>Click count: {count}</div>
    <button>Click me</button>
    </>
  )
}

export default Clicker

Wanneer we count nu veranderen (in de code) naar een ander getal zal die updaten in de browser.

03

USESTATE()

ONCLICK

We willen dat count omhoog gaat met 1 als we op de button klikken.

Je zou dit kunnen doen omdat het in vanilla javascript zo kan:

let count = 0;

const button = document.querySelector('button');
button?.addEventListener('click', () => {
   count++;
});

return (
   <>
    <div>Click count: {count}</div>
    <button>Click me</button>
   </>
)

NOT DONE in React en werkt niet want button bestaat op dat moment nog niet!!

03

USESTATE()

ONCLICK

We bekijken een andere mogelijkheid. We maken een function aan en gebruiken die bij de onClick.

const Clicker: React.FC = () => {

  let count = 0;

  const buttonClick = () => {
    count++;
    console.log(count);
  }

  return (
    <>
    <div>Click count: {count}</div>
    <button onClick={buttonClick}>Click me</button>
    </>
  )
}

We zien dat count niet omhoog gaat... Maar de count in de console wel... huh?

03

USESTATE()

ONCLICK

React weet op dit moment niet dat er iets is verandert. Met de useState hook kan dit wel.

import React from 'react'
import { useState } from 'react';

const Clicker: React.FC = () => {

  const [count, setCount] = useState(0);

  const buttonClick = () => {
    setCount(count + 1);
  }

  return (
    <>
    <div>Click count: {count}</div>
    <button onClick={buttonClick}>Click me</button>
    </>
  )
}

Gebruik een useState in de Clicker component.

03

USESTATE()

WE DIT IT!

Onze Clicker component werkt nu en is reactive.

EAT, SLEEP, REACT ... REPEAT

USEEFFECT()

04

04

USEEFFECT()

WHAT IS IT?

useEffect is een React Hook die wordt gebruikt om side-effects uit te voeren in function components.

  • Side-effects = alles wat buiten de component rendering gebeurt:

    • Data fetchen (API calls)

    • Event listeners toevoegen

    • Timers of intervals

    • Logging / analytics

  • Wordt uitgevoerd na de render van de component.

  • TypeScript gebruikt meestal geen speciale types, behalve bij event handlers of fetch responses.

04

USEEFFECT()

CLICKER +

We werken verder op het clicker voorbeeld en zullen nu zorgen dat onze count onthouden wordt als we de pagina refreshen.

We maken gebruik van de useEffect om aan te tonen hoe dit werkt.

import {useEffect} from 'react'

//...

  useEffect(() => {
    console.log(`Hello IMD`);
  });

  console.log(`Render Clicker`);
  
//...

Iedere keer wanneer we op de clicker klikken, komt de console.log() opnieuw.
Zowel in de useEffect als buiten de useEffect. We hebben hier weinig controle over...

04

USEEFFECT()

CLICKER +

useEffect aanvaard een 2de argument genaamd 'dependencies' (Array) die ons verteld wanneer die opnieuw mag uitgevoerd worden. Wanneer je een lege array meegeeft dan zeg je 'render enkel de eerste keer'.

We testen dit uit door onze 'hello IMD' een lege dependency mee te geven.

import {useEffect} from 'react'

//...

  useEffect(() => {
    console.log(`Hello IMD`);
  }, []);


  console.log(`Render Clicker`);
  
//...

Nu zien we effectief dat 'Hello IMD' maar 1 keer wordt aangeroepen maar 'Render Clicker' nog steeds iedere klik.

04

USEEFFECT()

CLICKER +

Als we een dependency meegeven zal de useEffect opnieuw uitgevoerd worden wanneer de state verandert.

Voeg nu de count toe aan de dependency array

import {useEffect} from 'react'

//...

  useEffect(() => {
    console.log(`Hello IMD`);
  }, [count]);
  
//...

We zien nu dat bij iedere klik de useEffect uitgevoerd wordt. Dit is precies de behaviour die we willen.

04

USEEFFECT()

CLICKER +

Nu we begrijpen hoe useEffect werkt, zullen we de count opslaan in onze localstorage via de useEffect.

Voeg volgende code toe in de useEffect om onze count op te slaan.

import {useEffect} from 'react'

//...

  useEffect(() => {
    localStorage.setItem('count', count.toString());
  }, [count]);
  
//...

De count wordt succesvol opgeslagen in de localstorage maar nu we willen deze ophalen de eerste keer dat onze component gerendered wordt.

04

USEEFFECT()

CLICKER +

We willen nu de count ophalen van de localstorage de eerste keer dat we onze component gebruiken. 

Voeg volgende code toe in de useEffect om onze count op te halen.

import {useEffect} from 'react'

//...

  useEffect(() => {
       const savedCount = parseInt(localStorage.getItem('count'));
       console.log(savedCount);
   }, []);

  useEffect(() => {
    localStorage.setItem('count', count.toString());
  }, [count]);
  
//...

We doen parseInt() omdat we een number terug willen krijgen en niet een string.

04

USEEFFECT()

CLICKER +

Wat als de gebruiker de applicatie voor de eerste keer had geopend en de count niet had staan in zijn/haar localStorage. Dan krijgen we NaN.

Om dit te fixen doen we het volgende:

import {useEffect} from 'react'

//...

  useEffect(() => {
       const savedCount = parseInt(localStorage.getItem('count') ?? '0');
       setCount(savedCount);
   }, []);

  useEffect(() => {
    localStorage.setItem('count', count.toString());
  }, [count]);
  
//...

Nu krijg je altijd een waarde. Merk op dat typescript hier ons ook aangeeft dat het 'null' kan zijn. Typescript is LIFE!

04

USEEFFECT()

ALTERNATIVE

Wat we ook kunnen doen i.p.v een useEffect te gebruiken voor initial render, is het plaatsen van de getItem in de useState zelf

Verander de code naar volgende:

import {useEffect} from 'react'

//...

const [count, setCount] = useState(parseInt(localStorage.getItem('count') ?? '0'));
  
//...

Nu kan je de useEffect zonder dependency weglaten en werkt alles perfect. Dit is goed voor synchronous initialisatie ('flickering' is er ook niet)  maar zodra je async werkt gebruik je beter useEffect.

EAT, SLEEP, REACT ... REPEAT

CONDITIONAL RENDERING

05

05

CONDITIONAL RENDERING

CONDITIONAL

We willen onze clicker conditional renderen met een toggle button. Zonder handmatig onze localStorage te clearen, zal de toggle dit voor ons doen.

Ga eerst naar App.tsx, voeg een button toe en maak een toggle function aan.

import {useState} from 'react'

function App() {

  const [hasClicker, setHasClicker] = useState(true);

  const handleToggleClicker = () => {
    setHasClicker(!hasClicker);
  }

  return (
    <>
      <button onClick={handleToggleClicker}>Toggle Clicker</button>
      <Clicker/>
    </>
  )
}

05

CONDITIONAL RENDERING

CONDITIONAL

Nu hebben we een toggle tussen true en false (hasClicker). De volgende stap is het conditional renderen van onze Clicker component a.d.h.v. hasClicker

Eerst zullen we de tekst aanpassen voor we components conditional zullen renderen.

import {useState} from 'react'

function App() {

  const [hasClicker, setHasClicker] = useState(true);
  console.log(hasClicker);

  const handleToggleClicker = () => {
    setHasClicker(!hasClicker);
  }

  return (
    <>
      <button onClick={handleToggleClicker}>{hasClicker ? 'Hide clicker' : 'Show clicker'}</button>
      <Clicker/>
    </>
  )
}

05

CONDITIONAL RENDERING

CONDITIONAL

Nu zullen we onze component conditional renderen.

Voeg volgende code in App.tsx

  return (
    <>
      <button onClick={handleToggleClicker}>{hasClicker ? 'Hide' : 'Show'} Clicker</button>
      {hasClicker ? <Clicker /> : null}
    </>
  )

Een kortere notatie kan ook als volgt:

  return (
    <>
      <button onClick={handleToggleClicker}>{hasClicker ? 'Hide' : 'Show'} Clicker</button>
      {hasClicker && <Clicker />}
    </>
  )

05

CONDITIONAL RENDERING

CONDITIONAL

Alles werkt zoals we willen... perfect! Maar we moeten nog onze count resetten als we onze component 'destroyen'. We maken gebruiken van de cleanup function in useEffect().

We maken de localStorage leeg door volgende te doen in onze useEffect. (Clicker.tsx)

useEffect(() => {
    console.log('Clicker mounted');
    
      return () => {
        console.log('Clicker unmounted');
      }
    }, []);

Vervang nu de cleanup met localStorage logica.

return () => {
        localStorage.removeItem('count');
}

EAT, SLEEP, REACT ... REPEAT

PROPS

06

PROPS

Stel dat we meerdere clickers willen ... dan kunnen we een fragment rond onze Clickers plaatsen.

Verander de code naar volgende in App.tsx: 

return (
    <>
      <button onClick={handleToggleClicker}>{hasClicker ? 'Hide' : 'Show'} Clicker</button>
      {hasClicker && <>
      <Clicker />
      <Clicker />
      <Clicker />
      </>}
    </>
  )

Onze Clickers werken perfect hoe we willen en de toggle doet wat hij moet doen.
Refresh de page eens? Oei! Niet wat we hadden verwacht...

06

PROPS

PROPS

We saven alle 3 'counts' in dezelfde localStorage. Dit kunnen we tegengaan door unieke keys te geven. We geven dus Props mee aan elke Clicker.

Voeg keyName toe aan alle 3 de Clicker's.

<Clicker keyName={'ClickerA'} />
<Clicker keyName={'ClickerB'} />
<Clicker keyName={'ClickerC'} />

We gebruiken hier niet het woord 'key' omdat dit een reserved word is in React en gebruikt wordt door react zelf.

In Clicker.tsx kan je dus props uit onze component halen.

interface ClickerProps {
    keyName: string;
}

const Clicker: React.FC<ClickerProps> = (props) => {

  const [count, setCount] = useState(parseInt(localStorage.getItem(count) ?? '0'));
  console.log(props);
  
//...

06

PROPS

PROPS

We oefenen hier op verder en zullen een kleur toevoegen aan de text. Voeg een color prop toe aan de Clicker's

in App.tsx

<Clicker keyName={'ClickerA'} color={'olive'}/>
<Clicker keyName={'ClickerB'} color={'orange'}/>
<Clicker keyName={'ClickerC'} color={'pink'}/>

06

PROPS

in Clicker.tsx

interface ClickerProps {
    keyName: string;
    color?: string;
}

const Clicker: React.FC<ClickerProps> = ({keyName, color}) => {

//...

<div style={{color}}>Click count: {count}</div>
<button onClick={buttonClick}>Click me</button>

Vergeet nooit je nieuwe prop toe te voegen aan je type/interface!

PROPS

In het geval dat er geen kleur is, kan je altijd een default value meegeven aan de prop zelf.

in App.tsx

<Clicker keyName={'ClickerA'} color={'olive'}/>
<Clicker keyName={'ClickerB'} color={'orange'}/>
<Clicker keyName={'ClickerC'} />

06

PROPS

in Clicker.tsx

interface ClickerProps {
    keyName: string;
    color?: string;
}

const Clicker: React.FC<ClickerProps> = ({keyName, color = "crimson"}) => {

BEYOND

Randomness is fun... en dit gaan we ook toevoegen. Hiervoor gebruiken we HSL om een random kleur te krijgen.

in App.tsx

<Clicker keyName={'ClickerA'} color={`hsl(${ Math.random() * 360}deg, 100%, 70%)`}/>
<Clicker keyName={'ClickerB'} color={`hsl(${ Math.random() * 360}deg, 100%, 70%)`}/>
<Clicker keyName={'ClickerC'} color={`hsl(${ Math.random() * 360}deg, 100%, 70%)`}/>

06

PROPS

CHILDREN

Een speciale of 'hidden' prop die beschikbaar is in React is 'children'. Hierdoor worden de zaken tussen een component gerendered.

in main.tsx

<App>
   <h1>My Clicker Game!</h1>
</App>

06

PROPS

in App.tsx

interface AppProps {
  children: React.ReactNode;
}

function App({children}: AppProps) {

//...

return (
    <>
      {children}
//...

EAT, SLEEP, REACT ... REPEAT

MOVING DATA (UP)

07

LIFTING STATE

We willen een globale counter maken die alle counters samentelt. Onze counts zullen we moeten doorgeven aan App. Probeer nooit values te halen uit de children. Dit kan potentieel je applicatie breken op een bepaald punt.

in App.tsx

const [count, setCount] = useState(0);

//...

  return (
    <>
      {children}
      <div>Total Count: {count}</div>

//...

07

MOVING DATA (UP)

LIFTING STATE

In onze App (parent) zullen we een function aanmaken die we zullen geven aan onze children (van App) om te gebruiken.

in App.tsx

const increment = () => {
    setCount(count + 1);
}

//...

  return (
    <>
      ...
      {hasClicker && <>
      <Clicker keyName={'ClickerA'} increment={increment} color={`hsl(${ Math.random() * 360}deg, 100%, 70%)`}/>
      <Clicker keyName={'ClickerB'} increment={increment} color={`hsl(${ Math.random() * 360}deg, 100%, 70%)`}/>
      <Clicker keyName={'ClickerC'} increment={increment} color={`hsl(${ Math.random() * 360}deg, 100%, 70%)`}/>
      </>}

//...

07

MOVING DATA (UP)

LIFTING STATE

Nu kunnen we in Clicker.tsx onze functie opvangen als prop en zo de count van App verhogen.

in Clicker.tsx

interface ClickerProps {
    keyName: string;
    color?: string;
    increment?: () => void;
}

const Clicker: React.FC<ClickerProps> = ({keyName, color = 'crimson', increment}) => {

//...

const buttonClick = () => {
   setCount(count + 1);
   if (increment) increment();
}

07

MOVING DATA (UP)

LIFTING STATE

Nu werkt het maar om dit aan alle children te geven en te zorgen dat alles die functie geeft... dit kan snel een 'mess' worden. Daarom maken we meestal gebruik van een 'global state'. Er zijn veel oplossingen en wij zullen later gebruik maken van een 'store' (Zustand).

07

MOVING DATA (UP)

EAT, SLEEP, REACT ... REPEAT

LOOPS

08

LOOPS

Wat als we nu meerdere Clickers willen maar niet telkens deze handmatig willen bijplaatsen. Dit kunnen we doen met loops

in main.tsx voeg je de 'clickerCount' prop toe aan App

<App clickerCount = {4}>
   <h1>My Clicker Game!</h1>
</App>

08

LOOPS

Vervolgens destructure je deze in de App component

interface AppProps {
  children: React.ReactNode;
  clickerCount?: number;
}

function App({children, clickerCount}: AppProps) {

LOOPS

Een For-loop is niet mogelijk in onze tsx files als rendering... Hoe doen we dit dan? Er zijn veel mogelijkheden maar wij focussen ons op de map-method.

in App.tsx maak je een lege Array aan met de clickerCount lengte.

//...

const testArray = Array(clickerCount);
console.log(testArray);

//...

We mapen over deze array maar dit werkt niet omdat we empty krijgen.

 testArray.map(() => {
    console.log('test');
  })

08

LOOPS

LOOPS

Wat kunnen we doen om dit wel werkende te krijgen? Gebruik maken van de spread operator.

in App.tsx verander je vorige code naar volgende

//...

const testArray = [...Array(clickerCount)]
console.log(testArray);

//...

Nu zien we dat het wel werkt, we krijgen 4 x undefined (dus niet empty).

08

LOOPS

LOOPS

Nu we dit weten kunnen we onze Clickers renderen aan de hand van onze count. 

Verander de rendering van de Clickers naar volgende code

//...

{[...Array(clickerCount)].map(() => (
     <Clicker keyName={`Clicker${index}`} increment={increment} color={`hsl(${ Math.random() * 360}deg, 100%, 70%)`}/>
))}
//...

Er is nog een error 'Each child should have a unique "key" prop. Dit kunnen we aanvullen met de index die map ons geeft. Alsook passen we de keyName aan.

//...

{[...Array(clickerCount)].map((value, index) => (
    <Clicker key={index} keyName={`Clicker${index}`} increment={increment} color={`hsl(${ Math.random() * 360}deg, 100%, 70%)`}/>
))}
      
//...

08

LOOPS

LOOPS

Maak altijd je components leesbaar door dit proper te formatten.

Verander de formatting in je components naar volgende.

{[...Array(clickerCount)].map((_, index) => (
      <Clicker 
          key={index} 
          keyName={`Clicker${index}`} 
          increment={increment} 
          color={`hsl(${ Math.random() * 360}deg, 100%, 70%)`}
      />
))}

08

LOOPS

EAT, SLEEP, REACT ... REPEAT

USEMEMO()

09

USEMEMO

Wanneer we op onze clickers klikken, zien we dat de kleuren steeds veranderen door de randomness. Dit gebeurt omdat de state in onze app wordt bijgewerkt, waardoor de hele app opnieuw wordt gerenderd — inclusief de Clickers.

We zullen eerst proberen om de kleuren buiten onze App te maken.

const colors = [
  `hsl(${ Math.random() * 360}deg, 100%, 70%)`,
  `hsl(${ Math.random() * 360}deg, 100%, 70%)`,
  `hsl(${ Math.random() * 360}deg, 100%, 70%)`,
]
console.log(colors);

function App({children, clickerCount}: AppProps) {
//...

09

USEMEMO()

USEMEMO

We kunnen nu in onze Clicker component de color array gebruiken die we hebben aangemaakt.

We zullen eerst proberen om de kleuren buiten onze App te maken.

<Clicker 
       key={index} 
       keyName={`Clicker${index}`} 
       increment={increment} 
       color={colors[index]}
/>

09

USEMEMO()

Perfect! Als we nu refreshen en klikken zie je dat de kleuren blijven... Hebben we het probleem opgelost? Niet echt.

PROBLEM 1

Stel dat we meerdere Apps maken dan zullen ze dezelfde colors hebben.

<App clickerCount = {3}>
   <h1>My Clicker Game!</h1>
</App>
<App clickerCount = {3}>
   <h1>My Clicker Game!</h1>
 </App>

09

USEMEMO()

Normaal maak je nooit meerdere App's aan maar dit concept slaat ook op andere componenten.

PROBLEM 2

Een ander probleem is als we onze clickerCount verhogen dan zijn er niet genoeg 'colors' in onze array.

Verander de clickerCount naar een hoger getal.

<App clickerCount = {6}>
    <h1>My Clicker Game!</h1>
</App>

09

USEMEMO()

We kunnen dit niet anticiperen en iedere keer handmatig colors bijplaatsen.

SOLVED

We maken de array met kleuren in de App. Vervolgens vullen we deze met een for-loop op basis van de clickerCount, zodat het aantal kleuren overeenkomt met het aantal clickers.

Voer volgende code in App.tsx

 const colors: string[] = [];

  if (!clickerCount) return;
  
  for(let i = 0; i < clickerCount; i++) {
    colors.push(`hsl(${ Math.random() * 360}deg, 100%, 70%)`);
  }

09

USEMEMO()

Dit werkt nu ongeacht hoeveel clickers je hebt.

CACHE

Door de nieuwe React Compiler sinds versie 19 hoeven we niet meer useMemo() te gebruiken om de kleuren te 'onthouden'. Indien je geen compiler hebt zal je zien dat de kleuren bij iedere klik nog steeds veranderen. 

09

USEMEMO()

In het geval van de laatste situatie,  bekijk je best eens de documentatie

EAT, SLEEP, REACT ... REPEAT

USEREF()

10

USEREF

Wat als we toegang willen aan DOM-elementen? Dit kunnen we doen met een useRef(). Dit zal handig zijn later in Three Fiber.

Maak een reference met useRef() in Clicker.tsx en link deze aan de button.

import React, { useState, useEffect, useRef} from 'react'

//...

const buttonRef = useRef<HTMLButtonElement>(null);
console.log(buttonRef);

//...

<div style={{color}}>Click count: {count}</div>
<button ref={buttonRef} onClick={buttonClick}>Click me</button>

10

USEREF()

We verwachten nu een console met de button maar we krijgen 'undefined'.
Klik eens op een klikker... Hmmmm

USEREF

In het begin van onze component is de button undefined. Dit komt omdat op het aanroepen van de functie de jsx (button) nog niet bestaat. Door te klikken op een clicker, rerendered react en zal de button wel bestaan.

Gebruik een useEffect() om toch een value te krijgen op de eerste render.

useEffect(() => {
    console.log('Clicker mounted');
    console.log(buttonRef.current);
    
//...

10

USEREF()

Nu hebben we toegang tot het DOM-element en kunnen we doen wat we willen.

 if (!buttonRef.current) return;
      buttonRef.current.style.backgroundColor = 'Orange';
      buttonRef.current.style.color = 'royalblue';

USEREF

useRef() zullen we vaak nodig hebben in React Three Fiber.
Dit om bv. een object te laten roteren of een animatie te laten afspelen.

10

USEREF()

TECH3/3 - React Basics

By Niels Minne

TECH3/3 - React Basics

  • 85