Pelin suoritustietojen poistaminen
Pelistä on toteutettu kaikki ne toiminnallisuudet, jotka tarvitaan pelin pelaamiseen. Joskus käyttäjä haluaa aloittaa pelaamisen alusta, joten toteutamme sitä varten toiminnallisuuden.
Huomaa, että tässä vaiheessa suoritustietojen poistaminen tuntuu epämielekkäältä, koska suoritustiedot katoavat kuitenkin sivupäivityksen myötä. Lisäämme tämän jälkeen toiminnallisuuden, jolla sovellus muistaa käyttäjän pelitilanteen sivupäivityksestä huolimatta.
Reset-komponentin luonti
Luo src/components-kansioon uusi tiedosto, anna sen nimeksi Reset.jsx
ja liitä sen sisällöksi seuraavat ohjelmarivit:
function Reset(props) {
return (
<div className="reset">
<button>Poista suoritustiedot</button>
</div>
);
}
export default Reset;
Edellä oleva komponentti ei sisällä vielä toiminnallisuutta, se renderöi ainoastaan napin. Kutsutaan tätä komponenttia seuraavaksi Settings-sivulla. Muokkaa src/pages-kansion Settings.jsx-tiedostoa seuraavasti:
-
Lisää tiedoston alkuu seuraava import-rivi:
import Reset from '../components/Reset';
-
Korvaa return-lauseen sisältä
TODO reset
-rivi seuraavalla rivillä:<Reset />
Settings-sivulle tuli tilastotietojen alle punainen nappi, jossa on tekstinä Poista suoritustiedot.

Komponentin tulostusnäkymän ehdollistaminen
Hyvään käytettävyyteen kuuluu, että käyttäjä ei pääse vahingossa poistamaan omia suoritustietojaan. Siksi napin painaminen ei saa poistaa tietoja kysymättä. Sen sijaan nappi avaakin lomakkeen, joka vaatii käyttäjältä aktiivista toimintaa tietojen poistamiseksi.
Reset-komponentilla tulee olemaan kaksi eri näkymää:
- oletusnäkymä, jossa on vain Poista suoritustiedot -nappi ja
- lomakenäkymä, jossa on tietojen poiston varmistava lomake.
Kun käyttäjä painaa oletusnäkymän nappia, niin ruudulle tulostuu lomakenäkymä. Tämä toteutetaan hyödyntämällä useState-tilamuuttujaa komponentin sisällä.
Muokkaa src/components-kansion Reset.jsx-komponenttia seuraavasti:
-
Lisää tiedoston alkuun seuraava useState-funktion tuonti.
import { useState } from 'react';
-
Lisää tilamuuttujan esittely Reset-funktion alkuun.
const [showForm, setShowForm] = useState(false);
Tämä esittelee totuusarvoisen tilamuuttujan, jonka alkuarvo on epätosi (
false
). -
Korvaa return-lause kokonaisuudessaan seuraavilla ohjelmariveillä:
if (showForm) { return ( <div>TODO lomakenäkymä</div> ); } else { return ( <div className="reset"> <button onClick={()=>{setShowForm(true)}}>Poista suoritustiedot</button> </div> ); }
Edellä koodissa muuttui kaksi asiaa. Ensiksi alkuperäinen return-lause sijoitettiin if-else-rakenteen else-osan sisällöksi. If-else-rakenne tulostaa jomman kumman näkymän riippuen showForm
-tilamuuttujan arvosta. Alkutilanteessa tulostetaan else-osan sisältö. Toiseksi nappiin lisättiin onClick
-käsittelijä, joka muuttaa showForm
-muuttujan arvoksi tosi (true
), kun nappia painetaan.
Käyttäjälle tämä toiminnallisuus näkyy niin, että ensimmäisen kerran Settings-sivulle tultaessa tilastotietojen alla näkyy nappi, kun käyttäjä painaa tuota nappia, niin napin tilalle tulee TODO lomakenäkymä
-teksti.

Lomakenäkymän toteuttaminen
Seuraavaksi toteutamme napin alta paljastuvan lomakenäkymän. Korvaa if-else-lauserakenteen ensimmäinen return-lause (eli se, jonka sisältönä on <div>TODO lomakenäkymä</div>
) seuraavalla:
return (
<div className="reset reset_box">
<h2>Suoritustietojen poistaminen</h2>
<p>Varoitus! Olet poistamassa kaikki,
mitä olet tähän mennessä kerännyt.
Jatkamalla tiedot nollautuvat ja peli alkaa
alusta.</p>
<p>Kirjoita teksti <span>{props.resetvalue}</span> alla olevaan kenttään.</p>
<div><input type="text" /></div>
<button>Poista suoritustiedot</button>
</div>
);
Nyt napin kautta avatuu jo lomakenäkymä, jossa ei ole vielä toiminnallisuutta.

Näkymän ohjerivi on hassu, sillä Reset-komponentille ei vielä välitetä resetValue
-arvoa, joka return-lauseen sisällä tulostetaan.
Muokkaa src/pages-kansion Settings.jsx-tiedoston return-lauseen sisällä oleva Reset-komponentin kutsu seuraavanlaiseksi:
<Reset resetvalue={props.stats.clicks} />
Tämän muutoksen myötä käyttäjän tekemien napautusten määrä tulostuu osaksi ohjetekstiä.

Lomakekentän hallinta
Lomakkeen kenttään pystyy tällä hetkellä syöttämään tietoa, mutta syötetyllä tiedolla ei ole vielä vaikutusta. Tallennetaan ensin käyttäjän syöttämä tieto tilamuuttujaan ja hyödynnetään tätä arvoa sen jälkeen.
Muokkaa src/components-kansiossa olevaa Reset-jsx-tiedostoa seuraavasti:
-
Lisää funktion alkuun, ennen return-lausetta seuraava useState-muuttujan esittely:
const [value, setValue] = useState("");
Tähän tilamuuttujaan tallennetaan käyttäjän lomakekenttään syöttämä teksti.
-
Muokkaa ensimmäisen return-lauseen sisällä olevaa lomakekentän määrittelevä rivi seuraavanlaiseksi:
<div><input type="text" value={value} /></div>
Muutoksessa
input
-elementinvalue
-arvoksi annetaanvalue
-tilamuuttujan arvo.
Nyt lomakekenttään ei pysty kirjoittamaan mitään tekstiä. Tämä johtuu siitä, että React kontrolloi lomakekentän sisältöä ja huolehtii siitä, että kentän sisältö on aina sama kuin value
-tilamuuttujan sisältö.
Jos haluamme mahdollistaa tekstin syöttämisen lomakekenttään, on sille määriteltävä käsittelijä, jota kutsutaan aina, kun lomakkeen sisältöä muutetaan.
Muokkaa ensimmäisen return-lauseen sisällä olevan lomakekentän määrittelyrivi seuraavanlaiseksi:
<div>
<input type="text"
value={value}
onChange={(e) => {setValue(e.target.value)}} />
</div>
Sen lisäksi, että sisältöä rivitettiin uudelleen, lisättiin input
-elementille onChange
-käsittelijä, joka kutsuu setValue
-funktiota aina kun lomakkeen kentän sisältöä muokataan. e
viittaa siihen elementtiin, jossa muutos tapahtui.
Lomakekentän arvon muuttuminen tapahtuu taustalla seuraavasti:
-
Kun käyttäjä syöttää lomakekenttään jonkin merkin, niin kentän
onChange
-käsittelijä käynnistyy ja kutsuu sille määritellyn funktion. -
Funktio käy poimimassa lomakekentän uuden arvon (
e.target.value
) ja tallentaa sensetValue
-funktion kauttavalue
-tilamuuttujan arvoksi. -
React tunnistaa, että
value
-tilamuuttujan arvo on päivittynyt, jolloin se renderöi uudelleen lomakekentän, jossavalue
-tilamuuttujan arvoa käytetään. -
Lomakekentän renderöinnin myötä lomakekentän arvoksi tulee
value
-tilamuuttujan arvo eli käyttäjän muokkaama arvo. -
Jos käyttäjä syöttää kenttään lisää sisältöä, niin tämä prosessi käynnistyy alusta.
Tämä prosessi selittää myös sen, miksi lomakekentän sisältöä ei pystynyt aiemmin muokkaamaan, kun kenttään ei ollut vielä lisätty onChange
-käsittelijää.
Napin aktivointi lomakekentän arvon perusteella
Lomakkeen käytettävyys edellyttää vielä palautetta siitä, milloin käyttäjän lomakekenttään syöttämä teksti on toivotunlainen. Tämä tapahtuu niin, että lomakkeen alla oleva nappi on lähtökohtaisesti disabloitu ja aktivoituu, kun nappia voidaan painaa.
Muokkaa ensimmäisen return-lauseen sisällä olevan button
-napin määrittely seuraavanlaiseksi:
<button disabled={props.resetvalue==value?false:true}>Poista suoritustiedot</button>
Tämä määrittelee napille disabled
-arvon riippuen siitä, vastaavatko käyttäjän syöttämä teksti ja komponentille välitetty resetvalue
toisiaan. Jos arvot eivät vastaa toisiaan, tulee disabled
-arvoksi tosi (true
), jolloin nappi ei ole aktiivinen. Napin tyylimääritteissä se on määritelty harmaaksi. Kun arvot vastaavat toisiaan, tulee disabled
-arvoksi epätosi (false
), jolloin nappi on aktiivinen ja sen värinä on punainen.

Suoritustietojen poiston käsittelijä
Lomake toimii tällä hetkellä muuten, mutta aktiivisen napin painaminen ei vaikuta mitään. Toteutetaan ensin pääkomponentille funktio, joka suorittaa tietojen poiston, välitetään funktio komponenttipuuta pitkin Reset-komponentille ja määritellään funktio napin onClick
-käsittelijäksi.
-
Muokkaa src-kansion App.jsx-tiedostoa seuraavasti:
- Lisää seuraava funktiomäärittely ennen return-lausetta:
const handleReset = () => { // Päivitetään tilamuuttujat alkuarvoihin. setStats(initialstats); setStoreitems(items); }
- Välitetään tämä funktio komponenttipuiuta pitkin AppRouter-komponentille. Muuta return-lauseen
AppRouter
-komponenttikutsu seuraavanlaiseksi:<AppRouter stats={stats} storeitems={storeitems} handleClick={handleClick} handlePurchase={handlePurchase} handleReset={handleReset} />
- Lisää seuraava funktiomäärittely ennen return-lausetta:
-
AppRouter-komponentilla välitetään funktio eteenpäin Settings-komponentille. Muokkaa src/components-kansion AppRouter.jsx-tiedoston reititysmäärityksissä
settings
-sivun määritys seuraavanlaiseksi:{ path: "settings", element: <Settings stats={props.stats} handleReset={props.handleReset} />},
-
Settings-komponentilla välitetään funktio eteenpäin Reset-komponentille. Muokkaa src/pages-kansion Settings.jsx-tiedostossa
Reset
-komponenttikutsu seuraavanlaiseksi:<Reset resetvalue={props.stats.clicks} handleReset={props.handleReset} />
-
Nyt
handleReset
-funktio on kuljettu komponenttipuuta pitkin App-komponentilta Reset-komponentille. Seuraavaksi kytkemme funktion napinonClick
-käsittelijäksi. Muokkaa src/components-kansion Reset.jsx-tiedostoa seuraavasti:-
Lisää funktion alkuun ennen ehtolauserakennetta seuraava funktiomäärite:
const handleReset = () => { // Nollataan pelin tiedot ja tyhjennetään tekstikenttä. props.handleReset(); setValue(""); }
-
Muokkaa ensimmäisessä return-lausessa oleva
button
-määrittely seuraavanlaiseksi:<button disabled={props.resetvalue==value?false:true} onClick={handleReset}>Poista suoritustiedot</button>
-
Näiden muutosten jälkeen sovellus nollaa käyttäjän pelitiedot nappia painettaessa.

Tuotelistan kopioinnin korjaaminen
Tarkkaavaisimmat huomasivat, että pelitietojen nollaamisen yhteydessä ostettujen tuotteiden määrät eivät nollaantuneet.

Tämä johtuu tavasta, jolla items
-taulukosta tehdään kopio. Kopiossa tehdään ns. matalatason kopio, jossa kopion tekeminen ei ulota syvemmille tasoille. Toisin sanoen kopioidussa taulukossa tuotteet ovat alkuperäisen taulukon tuotteita. Eri tapoja taulukon kopiointiin käsitellään artikkelissa How to clone an array in JavaScript.
Muuta src-kansion App.jsx-tiedoston handlePurchase
-funktion sisällä storeitems-muuttujan kopiointi seuraavanlaiseksi:
// Tehdään kopiot tilamuuttujista.
let newstoreitems = JSON.parse(JSON.stringify(storeitems));
Tämän muutoksen jälkeen myös tuotelista nollaantuu.

Muutosten vienti versiohallintaan
Viedään viimeisimmät muutokset versiohallintaan.
git add .
git commit -m "lisää suoritustietojen poistamisen"