React

React on Facebookin ja Instagramin Javascript-kirjasto käyttöliittymien tekemiseen.

Tämä sivu on päivitetty käyttämään function-komponentteja. Osa esimerkeistä voi vielä olla myös class-syntaksilla.

Kannattaa katsoa seuraava video: React Functional Components, Props, and JSX – React.js Tutorial for Beginners

JSX

Hello world

Yksinkertaisimmassa React-ohjelmassa liitetään html-dokumenttiin react-kirjasto, JSXTransformer-kirjasto ja kirjoitetaan script-elementin sisään oma yksinkertainen komponentti funktion muodossa ja renderoidaan se. Huom. script-elementin type-attribuutin arvon on oltava text/jsx.

kts. Quick Start ja tutorial

<!DOCTYPE html>
<html>
  <head>
    <title>Hello World</title>
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div id="main"></div>
    <script type="text/jsx">
// yksinkertainen komponentti, joka palauttaa tekstikappaleen jossa lukee haluttu nimi   
// komponentille annetut parametrit löytyvät this.props-objektista
const HelloWorld = function(props){
    return (
      <p>
        Hello {props.name}!
      </p>
    );
}
// näytetään main-tunnisteella varustetun lohkon sisällä edellä luotu oma komponentti
// esitettävä nimi annetaan attribuuttina
const root = ReactDOM.createRoot( document.getElementById('main'));
root.render(
    <HelloWorld name="Tommi" />
);
    </script>
  </body>
</html>        

React-function-komponentit

let Komponentti = function(props) {
     return ( <p>Hello World!</p> );
}

react ja silmukat

Reactin JSX-koodiin ei voi kirjoittaa kuin React-elementteja, html-elementtejä ja {}-sulkujen sisään funktiokutsuja tai laskutoimituksia ja muuttujien nimiä. Jos on tarve käyttää for-looppia tai muita vastaavia rakenteita on nämä suoritettava erikseen. Sisäkkäisten for-looppien tapauksessa on toinen looppi piilotettava erilliseen funktioon tai komponenttiin

Allaolevan esimerkin vanhaa versiota voi kokeilla pääteohjausmallissa.

let Test = function() {
    let taulukko = ["foo", "bar", "foobar", "barfoo"];
    let taulukko2 = [1, 2, 3, 4];
    let aputaulukko = [];
    // JSX-koodissa voi olla vain funktiokutsuja tai muuttujia
    // tässä tapauksessa taulukko[i] kelpaa hyvin <li></li>-rakenteen sisään
    // muista antaa jokin uniikki avain jokaiselle riville
    for(let i=0;i<taulukko.length;i++) {
          aputaulukko.push( <li key={i}>{taulukko[i]}</li> );               
    }
    
    aputaulukko = [];
    // entä jos on kaksi for-looppia?
    // tulostetaan sisempään listaan kaikki saman taulukon alkiot    
    // toinen for-looppi on piilotettava toiseen funktioon
//    for(let i=0;i<taulukko2.length;i++) {
//        aputaulukko.push( apufunktio(taulukko2[i], taulukko) );               
//    }
    // sama kuin edellä mutta käyttäen toista react-komponenttia
    for(let i=0;i<taulukko2.length;i++) {
        aputaulukko.push( <Apuluokka key={i} taulukko={taulukko} ulompi={taulukko2[i]} /> );               
    }
    
    return (
      <ul>
      { aputaulukko }
      </ul>
    ) 
    /* tämä ei toimi vaan tulee unexpected token -virheilmoitus
        return (
      <ul> {
        for(let i=0;i<taulukko.length;i++) {
              aputaulukko.push( <li>{taulukko[i]}</li> );               
        }}
      </ul>
    ) 
*/    
}

// tekee saman asian kuin alempana oleva apufunktio
let Apuluokka = function(props) {
    let aputaulukko = [];
    for(let i=0;i<props.taulukko.length;i++) {
        aputaulukko.push( <li key={i}>{props.taulukko[i]}</li> );               
    }
    return (
      <li>
      {props.ulompi} 
          <ul>
                { aputaulukko }
          </ul>
      </li>
    )
  }
});
 
// tekee sisemmän for-loopin, parametrina tuodaan ulomman listan teksti ja sisempään
// listaan vaadittava taulukko
function apufunktio(sarake, taulukko) {
    let aputaulukko = [];
    for(let i=0;i<taulukko.length;i++) {
        aputaulukko.push( <li key={i}>{taulukko[i]}</li> );               
    }
    return (
      <li key={sarake}>
      {sarake} 
          <ul>
                { aputaulukko }
          </ul>
      </li>
    )
}

Lomakkeet

Oletuksena Reactissa lomakkeet ovat kontrolloituja komponentteja. Kontrolloidussa lomakkeessa lomakkeen sisältö vastaa aina React-komponentin tilaa. Käytä kontrolloitua lomaketta aina kuin vain mahdollista. Jossain tilanteessa voit tehdä lomakkeesta myös kontrolloimattoman komponentin. Kts. esimerkit:

Lomakkeissa voi käyttää samoja tarkistuksia ja virheilmoituksia kuin normaalistikin. Kts. validointiesimerkki (function-versio, 2022) tai validointiesimerkki (class-versio, kontrolloimaton)

React-komponentin tila (setState)

Huomioi Reactista seuraavat seikat:

Asynkroninen setState

Huom!. Tilan päivittäminen tapahtuu asynkronisesti. Kts. Why is setState fiving me the wrong value

Asynkronisuus tarkoittaa, että ette voi tietää missä vaiheessa state oikeasti päivittyy. Esim. seuraavanlainen koodi erittäin todennäköisesti tulostaa vielä vanhan tilan eikä sitä mikä on juuri yritetty asettaa:

    uusi.joukkueet.push(joukkue);
    setState({...state, "joukkueet" : uusi });
    console.log(this.state.joukkueet);

Monimutkainen tila

Huom!. Jos tallennat tilaan objekteja tai taulukoita niin ole tarkkana tilaa kopioitaessa. Kts. esimerkki (lähdekoodi). Lisätietoa: How to update nested state properties in React ja Handling State in React: Four Immutable Approaches to Consider.

Jos tarvitset komponentissa muuttujia, jotka eivät vaikuta komponentin renderointiin, niin näitä ei tarvitse käyttää staten kautta vaan voit vapaasti keksiä omia. Esim. let foobar = "omajuttu"

Lisätietoa

Käyttäjien kommentit

Kommentoi Lisää kommentti
Informaatioteknologia - Jyväskylän yliopiston informaatioteknologian tiedekunta