React-demoja

Demo 1

Tämä demo käy läpi Full Stack open-kurssin osan 1 kohdan Reactin alkeet.

Projektin luonti

Tehdään Github-repon sisälle projektikansio demoille. Neljä demo tulevat kaikki tämän saman React-projektin sisälle. Avaa konsoli repon juurihakemistossa ja aja seuraava projektin luontikäsky:

npm create vite@latest demot -- --template react

Tämän jälkeen siirrytään kansioon ja käynnistetään reactin development server:

cd demot
npm install
npm run dev

Lähdekooditiedostot ovat src-kansiossa. App.jsx sisältää App-komponentin jonka sisälle teemme demojen tehtävät. Lisää alikansio components alikomponenteille.

node_modules-kansio sisältää Reactin asennettuja kirjastoja ja sitä ei haluta mukaan GitHub-repoon. Lisätään repon juurihakemistoon .gitignore-tiedosto:

node_modules

Kun olet käynnistänyt development serverin voit avata selaimessa osoitteen http://localhost:5173/.

Muutetaan App-komponentti yksinkertaisemmaksi:

import { useState } from 'react'
import './App.css'

function App() {

  return (
    <>
     <div className="App">
      <header className="App-header">
        <h1>React demot</h1>
      </header>
    </div>
    </>
  )
}

export default App    

Muokkaa myös App.css-tiedostoa:

.App-header {
  background-color: white;
  color: black;
  text-align: center;
  width: 100%;
}

.App {
  width: 800px;
}

body {
  place-items: start;
}    

Muuttujat

Reactissa muuttujat esitellään JavaScriptin tapaan. Kun viittaat muuttujaan return-osassa muuttuja ympäröidään aaltosuluilla.

function App() {
  const name = "Musti";
  const age = 10;

  return (
    <>
     <div className="App">
      <header className="App-header">
        <h1>React demot</h1>
      </header>
      <div className="App-body">
        <h2>Demo 1</h2>
        <p>Lemmikin nimi on {name} ja se on {age} vuotta vanha.</p>
      </div>
    </div>
    </>
  )
}

React-komponentti

Yleensä halutaan tehdä pienempiä komponentteja joita kutsutaan esimerkiksi App.jsx-tiedostossa. Komponentti tulee tuoda (import) sitä käyttävässä komponentissa.

  • Tee kansio components ja lisää sinne tiedosto Pet.jsx
  • Tallenna kuva lemmikistä assets-kansioon.
import imgPet from '../assets/demo_pet.png'

const Pet = () => {
    const name = "Musti";
    const age = 10;

    return (
        <div className='pet'>
            <h3>Lemmikki</h3>
            <p>nimi: {name}</p>
            <p>ikä: {age} vuotta</p>
            <img className="image" src={imgPet} alt="Kuva lemmikistä" />
        </div>
    );
};

export default Pet;  

App.jsx-tiedostolla tuodaan komponentti mukaan:

import Pet from './components/Pet.jsx'

Kutsutaan App.jsx-tiedostolla return-osassa Pet-komponenttia:

<div className="App-body">
<h2>Demo 1</h2>
<Pet />
</div>  

Tietojen välitys - props

Äskeinen komponentti tulostaa aina samat tiedot. Toimivampi komponentti saisi tiedot syötteenä ja osaisi tulostaa lemmikin tiedot näkyviin. Annetaan seuravaksi Pets-komponentille parametrit eli propsit syötteenä. Muuta App.jsx-tiedostoa seuraavasti:

 <Pet name="Musti" age="2" />

Pet.jsx-tiedostossa parametri propsin avulla voidaan tulostaa lemmikin tiedot:

const Pet = (props) => {

    return (
        <div className='pet'>
            <h3>Lemmikki</h3>
            <p>nimi: {props.name}</p>
            <p>ikä: {props.age} vuotta</p>
            <img className="image" src={imgPet} alt="Kuva lemmikistä" />
        </div>
    );
}; 

props on olio joka voidaan purkaa osiksi aaltosulkujen avulla. Usein on selkeämpää käyttää komponentilla muuttujia kuin props-oliota:

const Pet = ({name, age}) => {

    return (
        <div className='pet'>
            <h3>Lemmikki</h3>
            <p>nimi: {name}</p>
            <p>ikä: {age} vuotta</p>
            <img className="image" src={imgPet} alt="Kuva lemmikistä" />
        </div>
    );
};  

Olio

Komponentille välitettävä tieto on usein olio jossa on sisällä erilaisia muuttujia. App.jsx lähettääkin seuraavaksi komponentille olion. Määrittele ensin App.jsx-tiedostossa olio näin:

import imgPet from './assets/demo_pet.png'
const pet1 = {
  name: "Musti",
  age: 2,
  img: imgPet
}  

Lisätään tiedostoon Pet.jsx toinen komponentti PetObject. Nyt annetaan syötteenä olio.

const PetObject = ({pet}) => {
    return (
        <div className='pet'>
            <h3>{pet.name}</h3>
            <p>ikä: {pet.age} vuotta</p>
            <img className="image" src={pet.img} alt="Kuva lemmikistä" />
        </div>
    );
};  

Kun Pet.jsx-tiedosto sisältääkin kaksi komponenttia niin exportataan ne molemmat:

export {Pet, PetObject};

App.jsx-tiedostolla importataan Pet.jsx-tiedostosta kaksi komponenttia, muuta import-lausetta näin:

import {Pet, PetObject} from './components/Pet.jsx'

App.jsx kutsuu nyt PetObject-komponenttia pet1-oliolla:

<PetObject pet={pet1} />

Map ja taulukollinen olioita

Taulukon läpikäynti return-osassa tapahtuu map-rakenteen avulla. Map käy läpi taulukon ja palauttaa tuloksena uuden taulukon. Tee App.jsx:n alkuun taulukko joka sisältää useampia olioita.

Käytetyt kuvat (kuva1, kuva2, kuva3)
import imgPet from './assets/demo_pet.png'
import imgPet2 from './assets/demo_pet2.png'
import imgPet3 from './assets/demo_pet3.png'
const pet1 = {
  name: "Milo",
  age: 2,
  img: imgPet
}
const pet2 = {
  name: "Lucy",
  age: 2,
  img: imgPet
}
const pet3 = {
  name: "Bella",
  age: 3,
  img: imgPet3
}
const pet4 = {
  name: "Willow",
  age: 7,
  img: imgPet2
}
const pets = [pet1, pet2, pet3, pet4];  

Erotetaan Pets-komponenttiin taulukon läpikäynti. Jokaisesta lemmikistä luodaan Pet-komponentti. Lisää Pet.jsx-tiedostoon uusi komponentti Pets:

const Pets = ({pets}) => {
    return (
        <div className='pets'>
            {pets.map((pet, index) => (
                <PetObject key={index} pet={pet} />
            ))}
        </div>
    );
};

Kun tehdään map niin tämän lapsi tarvitsee key-attribuutin. Myöhemmin pyritään käyttämään uniikkia id-tietoa mutta tässä vaiheessa riittää indeksin hyödyntäminen key-attribuuttina.

App.jsx-tiedostossa tulee tuoda Pets-komponentti ja kutsua sitä PetObject-komponentin sijaan näin:

<h2>Demo 1</h2>
<Pets pets={pets} />