State

State en Props zijn een van de meest essentiële concepten die je moet begrijpen in React. Props dienen om informatie door een componenten structuur te geven, en state wordt gebruikt om applicaties interactief te maken. State wordt gebruikt om informatie bij te houden en deze aan te passen over de looptijd van je applicatie.

We zullen dat laatste demonstreren aan de hand van een voorbeeld. We gaan hiervoor terug naar ons InputView voorbeeld. Stel dat we elke keer de gebruiker iets intypt in de input box, dat we deze text willen laten tonen ergens anders in de applicatie. Dit is dus informatie die aangepast wordt over de looptijd van de applicatie.

const InputView = () => {
  const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {
    console.log(event.target.value);
  }
  
  ...

  return (
    <div>
      <input type="text" id="name" onChange={handleChange} />
    </div>
  )
}

We zouden foutief kunnen veronderstellen dat we dit probleem kunnen oplossen door een variabele te maken waar we de tekst van de input in kunnen opslagen. Dit zou er ongeveer als volgt kunnen uitzien.

// Opgepast: Deze code is FOUT! Doe dit nooit op deze manier
const InputView = () => {
  let name = ""; // Dit is fout!

  const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {
    name = event.target.value; // Dit is fout!
  }

  return (
    <div>
      <input type="text" id="name" onChange={handleChange} />
      <p>
        The name you typed is {name}
      </p>
    </div>
  )
}

Als je dit zou uitproberen dan ga je merken dat er niets gebeurt als je het input veld aanpast. Dit is omdat het rendering mechanisme hier niet wordt getriggerd. Dit wil zeggen dat het component niet opnieuw getekend zal worden, en dus de naam niet aangepast zal worden op je scherm.

Hoe lossen we het dan wel correct op? De oplossing hierboven is in principe niet ver van de juiste oplossing. We gaan hier in plaats van een variabele, een state aanmaken waar we de name in kunnen opslagen. Als deze state aangepast wordt zal het component wel opnieuw getekend worden (gerendered). We gaan hier gebruik maken van de useState hook om deze state aan te maken.

const [name, setName] = useState<string>('');

De useState functie heeft als argument een initiële state. Dit is de start waarde die de state zal krijgen als het component voor de eerste keer gerendered wordt. De functie geeft een array terug met twee elementen in: het eerste element is de huidige state en het tweede element is een functie waarmee je de state kan aanpassen. We geven ook aan welk type onze state zal bevatten door <string> mee te geven aan de useState functie.

Als we nu ons voorbeeld weer aanpassen komen we op de volgende code

const InputView = () => {
  const [name, setName] = useState<string>('');

  const handleChange: ChangeEventHandler<HTMLInputElement> = (event) => {
    setName(event.target.value);
  }

  return (
    <div>
      <input type="text" id="name" onChange={handleChange} />
      <p>
        The name you typed is {name}
      </p>
    </div>
  )
}

Als de gebruiker nu in het invoerveld iets ingeeft zal de handleEvent functie aangeroepen worden. Daarin wordt de setName methode opgeroepen die de waarde van de name state aanpast. Nadat deze is aangepast wordt het component terug gerendered. Dit wil zeggen dat de code van dit component terug uitgevoerd wordt, maar op dat moment zal de state met de name de nieuwe waarde bevatten en dus zal dit ook getoond worden aan de gebruiker.

Als je graag wil weten wanneer je component terug opnieuw wordt gerendered kan je in de code van de InputView component een console.log() statement zetten die afprint dat het component is gerenderd. Zo kan je in je chrome developer tools zien op welk moment het component terug opnieuw gerenderd wordt.

Voor de volledigheid passen we nu ook nog heel de input component aan zodat alle inputvelden event handlers hebben

const InputView = () => {
  const [name, setName] = useState<string>('');
  const [year, setYear] = useState<number>(1990);

  const handleNameChange: ChangeEventHandler<HTMLInputElement> = (event) => {
    setName(event.target.value);
  }

  const handleYearChange: ChangeEventHandler<HTMLInputElement> = (event) => {
    setYear(parseInt(event.target.value));
  }

  const handleClick: MouseEventHandler<HTMLInputElement> = (event) => {
    // does not do anything yet
  }

  return (
    <div>
      <input type="text" id="name" onChange={handleNameChange} value={name}/>
      <input type="number" id="year" name="year" min="1990" max="2021" onChange={handleYearChange} value={year}/>
      <input type="button" id="submit" onClick={handleClick} value="Add" />
      <p>
        You have typed {name} from the year {year}
      </p>
    </div>
  )
}

We hebben hier er ook voor gezorgd dat alle invoer velden nu ook de value attribuut gebruiken. Deze wordt gezet op de huidige waarde van de states. Zo zorgen we ervoor dat het inputveld altijd up-to-date is met de huidige waarde van de state. Dit noemen ze in react controlled components.

Last updated

Was this helpful?