` contained a `Counter`. But when you swapped in a `p`, React removed the `Counter` from the UI tree and destroyed its state.
+Tässä vaihdat _eri_ komponenttityyppejä samassa sijainnissa. Aluksi `
`:n ensimmäinen lapsi oli `Counter`. Mutta kun vaihdat `
`:ksi, React poistaa `Counter`n UI puusta ja tuhoaa sen tilan.
-
+
-When `Counter` changes to `p`, the `Counter` is deleted and the `p` is added
+Kun `Counter` vaihtuu `p`:ksi, `Counter` poistetaan ja `p` lisätään
@@ -591,15 +589,15 @@ When `Counter` changes to `p`, the `Counter` is deleted and the `p` is added
-
+
-When switching back, the `p` is deleted and the `Counter` is added
+Vaihdettaessa takaisin, `p` poistetaan ja `Counter` lisätään
-Also, **when you render a different component in the same position, it resets the state of its entire subtree.** To see how this works, increment the counter and then tick the checkbox:
+Huomaathan, **kun renderöit eri komponentin samassa sijainnissa, se nollaa sen koko alipuun tilan.** Nähdäksesi, miten tämä toimii, lisää laskuri ja valitse sitten valintaruutu:
@@ -688,13 +686,13 @@ label {
-The counter state gets reset when you click the checkbox. Although you render a `Counter`, the first child of the `div` changes from a `div` to a `section`. When the child `div` was removed from the DOM, the whole tree below it (including the `Counter` and its state) was destroyed as well.
+Laskurin tila nollautuu kun valintaruutu valitaan. Vaikka renderöit `Counter`:n, ensimmäinen ``:n lapsi muuttuu `
`:stä `
`:ksi. Kun `div`:n lapsi poistettiin DOM:sta, sen koko alipuu (mukaan lukien `Counter` ja sen tila) tuhottiin.
-
+
-When `section` changes to `div`, the `section` is deleted and the new `div` is added
+Kun `section` muuttuu `div`:ksi, `section` poistetaan ja uusi `div` lisätään
@@ -702,21 +700,21 @@ When `section` changes to `div`, the `section` is deleted and the new `div` is a
-
+
-When switching back, the `div` is deleted and the new `section` is added
+Vaihdettaessa takaisin, `div` poistetaan ja uusi `section` lisätään
-As a rule of thumb, **if you want to preserve the state between re-renders, the structure of your tree needs to "match up"** from one render to another. If the structure is different, the state gets destroyed because React destroys state when it removes a component from the tree.
+Nyrkkisääntönä, **jos haluat säilyttää tilan renderöintien välillä, puun rakenteen on oltava "sama"** renderöinnistä toiseen. Jos rakenteet ovat erilaiset, tila tuhotaan, sillä React tuhoaa tilan, kun se poistaa komponentin puusta.
-This is why you should not nest component function definitions.
+Tämän takia sinun ei tulisi määritellä komponenttien sisällä komponentteja.
-Here, the `MyTextField` component function is defined *inside* `MyComponent`:
+Tässä, `MyTextField`-komponenttia määritellään `MyComponent`-komponentin *sisällä*:
@@ -750,14 +748,13 @@ export default function MyComponent() {
-
-Every time you click the button, the input state disappears! This is because a *different* `MyTextField` function is created for every render of `MyComponent`. You're rendering a *different* component in the same position, so React resets all state below. This leads to bugs and performance problems. To avoid this problem, **always declare component functions at the top level, and don't nest their definitions.**
+Joka kerta kun klikkaat painikkeesta, syötteen tila häviää! Tämä johtuu siitä, että *eri* `MyTextField`-funktio luodaan joka renderöinnille `MyComponent`:sta. Renderöit *eri* komponentin samassa sijainnissa, joten React nollaa kaiken tilan alapuolella. Tämä johtaa virheisiin ja suorituskykyongelmiin. Välttääksesi tämän ongelman, **määrittele komponenttien funktiot aina ylemmällä tasolla, äläkä sisällytä niiden määrittelyjä.**
-## Resetting state at the same position {/*resetting-state-at-the-same-position*/}
+## Tilan nollaaminen samassa sijainnissa {/*resetting-state-at-the-same-position*/}
-By default, React preserves state of a component while it stays at the same position. Usually, this is exactly what you want, so it makes sense as the default behavior. But sometimes, you may want to reset a component's state. Consider this app that lets two players keep track of their scores during each turn:
+Oletuksena React säilyttää komponentin tilan, kun se pysyy samassa sijainnissa. Yleensä tämä on juuri sitä, mitä haluat, joten se on järkevää oletusarvoa. Mutta joskus haluat nollata komponentin tilan. Harkitse tätä sovellusta, joka antaa kahdelle pelaajalle mahdollisuuden pitää kirjaa heidän pisteistään jokaisella vuorollaan:
@@ -769,14 +766,14 @@ export default function Scoreboard() {
return (
{isPlayerA ? (
-
+
) : (
-
+
)}
{
setIsPlayerA(!isPlayerA);
}}>
- Next player!
+ Seuraava pelaaja!
);
@@ -797,9 +794,9 @@ function Counter({ person }) {
onPointerEnter={() => setHover(true)}
onPointerLeave={() => setHover(false)}
>
- {person}'s score: {score}
+ {person}n pisteet: {score}
setScore(score + 1)}>
- Add one
+ Lisää yksi
);
@@ -827,19 +824,19 @@ h1 {
-Currently, when you change the player, the score is preserved. The two `Counter`s appear in the same position, so React sees them as *the same* `Counter` whose `person` prop has changed.
+Tällä hetkellä, kun vaihdat pelaajaa, tila säilyy. Kaksi `Counter`-komponenttia näkyy samassa sijainnissa, joten React näkee ne *samana* `Counter`-komponenttina, jonka `person`-prop on muuttunut.
-But conceptually, in this app they should be two separate counters. They might appear in the same place in the UI, but one is a counter for Taylor, and another is a counter for Sarah.
+Mutta tässä sovelluksessa niiden tulisi olla eri laskureita. Ne saattavat näkyä samassa kohdassa käyttöliittymää, mutta toinen laskuri on Tommin ja toinen laskuri Saran.
-There are two ways to reset state when switching between them:
+On kaksi tapaa nollata tila kun vaihdetaan niiden välillä:
-1. Render components in different positions
-2. Give each component an explicit identity with `key`
+1. Renderöi komponentit eri sijainneissa
+2. Anna kullekin komponentille eksplisiittinen identiteetty `key` propilla
-### Option 1: Rendering a component in different positions {/*option-1-rendering-a-component-in-different-positions*/}
+### 1. Vaihtoehto: Komponentin renderöiminen eri sijainneissa {/*option-1-rendering-a-component-in-different-positions*/}
-If you want these two `Counter`s to be independent, you can render them in two different positions:
+Jos haluat, että nämä kaksi `Counter`-komponenttia ovat erillisiä, voit renderöidä ne eri sijainneissa:
@@ -851,15 +848,15 @@ export default function Scoreboard() {
return (
{isPlayerA &&
-
+
}
{!isPlayerA &&
-
+
}
{
setIsPlayerA(!isPlayerA);
}}>
- Next player!
+ Seuraava pelaaja!
);
@@ -880,9 +877,9 @@ function Counter({ person }) {
onPointerEnter={() => setHover(true)}
onPointerLeave={() => setHover(false)}
>
- {person}'s score: {score}
+ {person}n pisteet: {score}
setScore(score + 1)}>
- Add one
+ Lisää yksi
);
@@ -910,42 +907,42 @@ h1 {
-* Initially, `isPlayerA` is `true`. So the first position contains `Counter` state, and the second one is empty.
-* When you click the "Next player" button the first position clears but the second one now contains a `Counter`.
+* Aluksi, `isPlayerA` on arvoltaan `true`. Joten ensimmäinen sijainti sisältää `Counter` tilan ja toinen on tyhjä.
+* Kun klikkaat "Seuraava pelaaja" painiketta, ensimmäinen sijainti tyhjenee ja seuraava sisältää `Counter`:n.
-
+
-Initial state
+Alkuperäinen tila
-
+
-Clicking "next"
+Painetaan "Seuraava pelaaja"
-
+
-Clicking "next" again
+Painetaan "Seuraava pelaaja" uudelleen
-Each `Counter`'s state gets destroyed each time its removed from the DOM. This is why they reset every time you click the button.
+Kunkin `Counter`:n tila tuhotaan joka kerta kun sen poistetaan DOM:sta. Tämän takia ne nollautuvat joka kerta kun painat painiketta.
-This solution is convenient when you only have a few independent components rendered in the same place. In this example, you only have two, so it's not a hassle to render both separately in the JSX.
+Tämä ratkaisu on kätevä, kun sinulla on vain muutamia riippumattomia komponentteja, jotka renderöidään samassa paikassa. Tässä esimerkissä sinulla on vain kaksi, joten ei ole hankalaa renderöidä molemmat erikseen JSX:ssä.
-### Option 2: Resetting state with a key {/*option-2-resetting-state-with-a-key*/}
+### 2. Vaihtoehto: Tilan nollaaminen avaimella {/*option-2-resetting-state-with-a-key*/}
-There is also another, more generic, way to reset a component's state.
+On myös toinen, yleisempi tapa, jolla voit nollata komponentin tilan.
-You might have seen `key`s when [rendering lists.](/learn/rendering-lists#keeping-list-items-in-order-with-key) Keys aren't just for lists! You can use keys to make React distinguish between any components. By default, React uses order within the parent ("first counter", "second counter") to discern between components. But keys let you tell React that this is not just a *first* counter, or a *second* counter, but a specific counter--for example, *Taylor's* counter. This way, React will know *Taylor's* counter wherever it appears in the tree!
+Olet saattanut nähdä `key` propseja kun [renderöitiin listoja.](/learn/rendering-lists#keeping-list-items-in-order-with-key) Avaimet eivät ole vain listoille! Voit käyttää avaimia saadaksesi Reactin tunnistamaan erot komponenttien välillä. Oletuksena, React käyttää järjestystä ("ensimmäinen laskuri", "toinen laskuri") erottaakseen komponentit toisistaan. Mutta avaimilla voit kertoa Reactille, että tämä ei ole vain *ensimmäinen* laskuri ,tai *toinen* laskuri, vaan tarkemmin--esimerkiksi *Tommin* laskuri. Näin React tietää *Tommin* laskurin joka kerta kun näkee sen puussa!
-In this example, the two ` `s don't share state even though they appear in the same place in JSX:
+Tässä esimerkissä, kaksi ` `:a eivät jaa tilaa vaikka ne näyttävät samassa paikassa JSX:ssä:
@@ -1015,7 +1012,7 @@ h1 {
-Switching between Taylor and Sarah does not preserve the state. This is because **you gave them different `key`s:**
+Tila säily vaikka Tommin ja Saran välillä vaihdetaan. Tämä tapahtuu **koska annoit niille eri `key`:t.**
```js
{isPlayerA ? (
@@ -1025,19 +1022,19 @@ Switching between Taylor and Sarah does not preserve the state. This is because
)}
```
-Specifying a `key` tells React to use the `key` itself as part of the position, instead of their order within the parent. This is why, even though you render them in the same place in JSX, React sees them as two different counters, and so they will never share state. Every time a counter appears on the screen, its state is created. Every time it is removed, its state is destroyed. Toggling between them resets their state over and over.
+Sen sijaan että komponentin sijainti tulisi järjestyksestä pääkomponentissa, `key`:n määrittäminen kertoo Reactille, että `key` itsessään on osa sijaintia. Tämän takia vaikka renderöit ne samassa sijainnissa JSX:ssä, Reactin perspektiivistä nämä ovat kaksi eri laskuria. Seurauksena, ne eivät koskaan jaa tilaa. Joka kerta kun laskuri näkyy ruudulla, sen tila on luotu. Joka kerta kun poistetaan, sen tila tuhotaan. Näiden välillä vaihtelu nollaa ja tuhoaa niiden tilan uudelleen ja uudelleen.
-Remember that keys are not globally unique. They only specify the position *within the parent*.
+Muista, että avaimet eivät ole globaalisti uniikkeja. Ne määrittelevät sijainnin *komponentin sisällä*.
-### Resetting a form with a key {/*resetting-a-form-with-a-key*/}
+### Lomakkeen nollaaminen avaimella {/*resetting-a-form-with-a-key*/}
-Resetting state with a key is particularly useful when dealing with forms.
+Tilan nollaaminen on erittäin hyödyllistä kun käsitellään lomakkeita.
-In this chat app, the `` component contains the text input state:
+Tässä chat-sovelluksessa, `` komponentti sisältää tilan tekstisyötteelle:
@@ -1132,17 +1129,17 @@ textarea {
-Try entering something into the input, and then press "Alice" or "Bob" to choose a different recipient. You will notice that the input state is preserved because the `` is rendered at the same position in the tree.
+Kokeile syöttää jotain kenttään ja painaa "Alice" tai "Bob" valitaksesi eri vastaanottajan. Huomaat, että syöte säilyy, koska `` renderöidään samassa sijainnissa puussa.
-**In many apps, this may be the desired behavior, but not in a chat app!** You don't want to let the user send a message they already typed to a wrong person due to an accidental click. To fix it, add a `key`:
+**Monissa sovelluksisa, tämä saattaa olla haluttu ominaisuus, mutta ei chat-sovelluksessa!** Et halua käyttäjän lähettävän kirjoitettua viestiä väärälle henkilölle vanhingollisen klikkauksen seurauksena. Korjataksesi tämän, lisää `key`:
```js
```
-This ensures that when you select a different recipient, the `Chat` component will be recreated from scratch, including any state in the tree below it. React will also re-create the DOM elements instead of reusing them.
+Tämä varmistaa, että kun valitset eri vastaanottajan, `Chat` komponentti tullaan luomaan alusta, mukaan lukien tila puussa sen alla. React tulee myös luomaan uudelleen DOM elementit niiden uudelleenkäytön sijaan.
-Now switching the recipient always clears the text field:
+Nyt vaihtaminen vastaanottajien välillä tyhjää tekstisyötteen:
@@ -1239,24 +1236,24 @@ textarea {
-#### Preserving state for removed components {/*preserving-state-for-removed-components*/}
+#### Tilan säilyttäminen poistetuille komponenteille {/*preserving-state-for-removed-components*/}
-In a real chat app, you'd probably want to recover the input state when the user selects the previous recipient again. There are a few ways to keep the state "alive" for a component that's no longer visible:
+Oikeassa chat-sovelluksessa, haluaisit varmaankin palauttaa syötteen kun käyttäjä valitsee edellisen vastaanottajan uudestaan. On useita tapoja pitää tila "hengissä" komponentille, joka ei ole enää näkyvissä:
-- You could render _all_ chats instead of just the current one, but hide all the others with CSS. The chats would not get removed from the tree, so their local state would be preserved. This solution works great for simple UIs. But it can get very slow if the hidden trees are large and contain a lot of DOM nodes.
-- You could [lift the state up](/learn/sharing-state-between-components) and hold the pending message for each recipient in the parent component. This way, when the child components get removed, it doesn't matter, because it's the parent that keeps the important information. This is the most common solution.
-- You might also use a different source in addition to React state. For example, you probably want a message draft to persist even if the user accidentally closes the page. To implement this, you could have the `Chat` component initialize its state by reading from the [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), and save the drafts there too.
+- Voit renderöidä _kaikki_ chatit yhden sijaan, ja piilottaa loput CSS:llä. Keskusteluja ei tultaisi poistamaan puusta, joten niiden paikallinen tila säilyisi. Tämä tapa toimii yksinkertaisille käyttöliittymille, mutta se voi koitua erittäin hitaaksi, jos piilotetut puut ovat suuria ja sisältävät paljon DOM nodeja.
+- Voit [nostaa tilan ylös](/learn/sharing-state-between-components) ja pitää viestiluonnokset jokaiselle vastaanottajalle pääkomponentissa. Tällä tavalla, kun lapsikomponentti poistetaan, se ei haittaa, sillä pääkomponentti pitää yllä tärkeät tiedot. Tämä on yleisin ratkaisu.
+- Saatat myös käyttää eri lähdettä Reactin tilan lisäksi. Esimerkiksi, saatat haluta viestiluonnoksen säilyvän vaikka käyttäjä vahingossa sulkisi sivun. Tämän tehdäksesi, voisit asettaa `Chat` komponentin alustamaan tilan lukemalla [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage):a ja tallentamaan myös luonnokset sinne.
-No matter which strategy you pick, a chat _with Alice_ is conceptually distinct from a chat _with Bob_, so it makes sense to give a `key` to the `` tree based on the current recipient.
+Riippumatta siitä minkä strategian valitset, chatti _Alicen kanssa_ on havainnollisesti eri kuin _Bobin kanssa_, joten on järkevää antaa `` komponentille `key` propsi, joka pohjautuu nykyiseen vastaanottajaan.
-- React keeps state for as long as the same component is rendered at the same position.
-- State is not kept in JSX tags. It's associated with the tree position in which you put that JSX.
-- You can force a subtree to reset its state by giving it a different key.
-- Don't nest component definitions, or you'll reset state by accident.
+- React pitää tilan niin pitkään kuin sama komponentti on renderöity samassa sijainnissa.
+- Tilaa ei pidetä JSX tageissa. Se liittyy puun sijaintiin, johon laitat JSX:n.
+- Voit pakottaa alipuun nollaamaan tilansa antamalla sille toisen avaimen.
+- Älä sijoita komponenttimäärityksiä toistensa sisään, tai nollaat tilan vahingossa.
@@ -1264,9 +1261,9 @@ No matter which strategy you pick, a chat _with Alice_ is conceptually distinct
-#### Fix disappearing input text {/*fix-disappearing-input-text*/}
+#### Korjaa katoava syöttöteksti {/*fix-disappearing-input-text*/}
-This example shows a message when you press the button. However, pressing the button also accidentally resets the input. Why does this happen? Fix it so that pressing the button does not reset the input text.
+Tämä esimerkki näyttää vistin kun painat painiketta. Kuitenkin painikkeen painaminen vahingossa nollaa syötteen. Miksi näin tapahtuu? Korjaa se, jotta painikkeen painaminen ei nollaa tekstisyötettä.
@@ -1315,9 +1312,9 @@ textarea { display: block; margin: 10px 0; }
-The problem is that `Form` is rendered in different positions. In the `if` branch, it is the second child of the ``, but in the `else` branch, it is the first child. Therefore, the component type in each position changes. The first position changes between holding a `p` and a `Form`, while the second position changes between holding a `Form` and a `button`. React resets the state every time the component type changes.
+Ongelma on siinä, että `Form` renderöidään useissa eri sijainneissa. Jos-haarassa se on `
`:n toinen lapsi, mutta ehtolauseen `else` haarassa se on ensimmäinen. Tästä syystä komponentin tyyppi kummassakin sijainnissa muuttuu. Ensimmäinen sijainti muuttuu `p`:n ja `Form`:n välillä, kun taas toisessa `Form`:n ja `button`:in välillä. React nollaa tilan joka kerta, kun komponentin tyyppi muuttuu.
-The easiest solution is to unify the branches so that `Form` always renders in the same position:
+Helpoin ratkaisu on yhdistää haarat siten, että `Form` renderöidään aina samassa sijainnissa:
@@ -1363,7 +1360,7 @@ textarea { display: block; margin: 10px 0; }
-Technically, you could also add `null` before `
` in the `else` branch to match the `if` branch structure:
+Teknisesti ottaen, voisit myös lisätä `null` ennen `
` ehtolauseen `else` haaraan vastatakseen ehtolauseen ensimmäisen haaran rakennetta:
@@ -1411,19 +1408,19 @@ textarea { display: block; margin: 10px 0; }
-This way, `Form` is always the second child, so it stays in the same position and keeps its state. But this approach is much less obvious and introduces a risk that someone else will remove that `null`.
+Tällä tavalla, `Form` on aina toinen lapsi, joten se pysyy samassa sijainnissa ja säilyttää tilansa. Tämä tapa ei ole kuitenkaan niin itsestään selvää ja lisää mahdollisuuden riskille, että joku muu poistaa `null` maininnan.
-#### Swap two form fields {/*swap-two-form-fields*/}
+#### Vaihda kaksi lomakekenttää {/*swap-two-form-fields*/}
-This form lets you enter first and last name. It also has a checkbox controlling which field goes first. When you tick the checkbox, the "Last name" field will appear before the "First name" field.
+Tähän lomakkeeseen voit syöttää etu- ja sukunimen. Siinä on myös valintaruutu, jonka perusteella päätellään kumpi kenttä tulee ensin. Kun valitset valintaruudun, "Last name" näkyy ennen "First name" kenttää.
-It almost works, but there is a bug. If you fill in the "First name" input and tick the checkbox, the text will stay in the first input (which is now "Last name"). Fix it so that the input text *also* moves when you reverse the order.
+Se melkein toimii, mutta siinä on bugi. Jos täytät "First name" syötteeseen ja valitset valintaruudun, teksti pysyy ensimmäisessä tekstisyötteessä (joka on nyt "Last name"). Korjaa se siten, että tekstisyöte *myös* liikkuu kun vaihdat niiden sijaintia.
-It seems like for these fields, their position within the parent is not enough. Is there some way to tell React how to match up the state between re-renders?
+Näyttää siltä, että näille kentille sijainti pääkomponentin sisällä ei riitä. Onko jokin tapa kertoa Reactille miten uudelleen renderöintien välillä tila voidaan nollata?
@@ -1487,7 +1484,7 @@ label { display: block; margin: 10px 0; }
-Give a `key` to both `` components in both `if` and `else` branches. This tells React how to "match up" the correct state for either `` even if their order within the parent changes:
+Anna molemmille `` komponenteille `key` kummassakin `if` ja `else` haaroissa. Tämä kertoo Reactille miten nollata tila kummallekkin `` komponentille vaikka niiden sijainti pääkomponentissa muuttuisi:
@@ -1549,11 +1546,11 @@ label { display: block; margin: 10px 0; }
-#### Reset a detail form {/*reset-a-detail-form*/}
+#### Nollaa yhteystietolomake {/*reset-a-detail-form*/}
-This is an editable contact list. You can edit the selected contact's details and then either press "Save" to update it, or "Reset" to undo your changes.
+Tämä on muokattava yhteystietolista. Voit muokata valitun henkilön tietoja ja sitten painaa "Tallenna" päivittääksesi sen tai "Reset" palauttaaksesi muutoksesi.
-When you select a different contact (for example, Alice), the state updates but the form keeps showing the previous contact's details. Fix it so that the form gets reset when the selected contact changes.
+Kun valitset eri yhteystiedon (esimerkiksi, Alice), tila päivittyy, mutta lomake näyttää silti edellisen yhteystiedon tiedot. Korjaa se siten, että lomake nollautuu kun valittu yhteystieto muuttuu.
@@ -1705,7 +1702,7 @@ button {
-Give `key={selectedId}` to the `EditContact` component. This way, switching between different contacts will reset the form:
+Anna `key={selectedId}` propsi `EditContact` komponentille. Tällä tavalla vaihtaminen yhteystietojen välillä nollaa lomakkeen:
@@ -1858,13 +1855,13 @@ button {
-#### Clear an image while it's loading {/*clear-an-image-while-its-loading*/}
+#### Nollaa kuva kun se lataa {/*clear-an-image-while-its-loading*/}
-When you press "Next", the browser starts loading the next image. However, because it's displayed in the same ` ` tag, by default you would still see the previous image until the next one loads. This may be undesirable if it's important for the text to always match the image. Change it so that the moment you press "Next", the previous image immediately clears.
+Kun painat "Next", selain alkaa lataamaan seuraavaa kuvaa. Kuitenkin, koska se näytetään samassa ` `-elementissä, oletuksena näet edellisen kuvan ennen kuin seuraava latautuu. Tämä voi olla epätoivottavaa, jos on tärkeää, että teksti aina vastaa kuvaa. Muuta sitä niin, että heti kun painat "Next", edellinen kuva poistuu välittömästi.
-Is there a way to tell React to re-create the DOM instead of reusing it?
+Onko tapaa kertoa Reactille että se pitäisi luoda DOM uudelleen sen sijaan että se käyttäisi sitä uudelleen?
@@ -1934,7 +1931,7 @@ img { width: 150px; height: 150px; }
-You can provide a `key` to the ` ` tag. When that `key` changes, React will re-create the ` ` DOM node from scratch. This causes a brief flash when each image loads, so it's not something you'd want to do for every image in your app. But it makes sense if you want to ensure the image always matches the text.
+Voit antaa ` ` tagille `key` propsin. Kun `key` muuttuu, React luo ` ` DOM:n uudelleen. Tämä aiheuttaa lyhyen välähdyksen kun jokainen kuva latautuu, joten et halua tehdä tätä jokaiselle kuvalle sovelluksessasi. Mutta se on järkevää jos haluat varmistaa että kuva aina vastaa tekstiä.
@@ -2002,11 +1999,11 @@ img { width: 150px; height: 150px; }
-#### Fix misplaced state in the list {/*fix-misplaced-state-in-the-list*/}
+#### Korjaa väärin sijoitettu tila listassa {/*fix-misplaced-state-in-the-list*/}
-In this list, each `Contact` has state that determines whether "Show email" has been pressed for it. Press "Show email" for Alice, and then tick the "Show in reverse order" checkbox. You will notice that it's _Taylor's_ email that is expanded now, but Alice's--which has moved to the bottom--appears collapsed.
+Tässä listassa, jokaisella `Contact`:lla on tila joka määrittää onko "Show email" painettu sille. Paina "Show email" Alice:lle ja sitten valitse "Näytä käänteisessä järjestyksessä". Huomaat että _Taylor:n_ sähköposti on nyt laajennettu, mutta Alice:n--joka on siirtynyt alimmaiseksi--on suljettu.
-Fix it so that the expanded state is associated with each contact, regardless of the chosen ordering.
+Korjaa tila niin että laajennettu tila on yhdistetty jokaiseen yhteystietoon, riippumatta valitusta järjestyksestä.
@@ -2096,16 +2093,16 @@ button {
-The problem is that this example was using index as a `key`:
+Esimerkin ongelma johtui siitä että tässä esimerkissä käytettiin indeksiä `key`:nä:
```js
{displayedContacts.map((contact, i) =>
```
-However, you want the state to be associated with _each particular contact_.
+Haluat kuitenkin, että tila on yhdistetty _jokaiseen yksittäiseen yhteystietoon_.
-Using the contact ID as a `key` instead fixes the issue:
+Yhteystiedon ID:n käyttäminen `key`:nä korjaa ongelman:
@@ -2193,7 +2190,7 @@ button {
-State is associated with the tree position. A `key` lets you specify a named position instead of relying on order.
+Tila on yhdistetty puun sijaintiin. `key` antaa sinun määrittää nimetyn sijainnin sijasta riippumatta järjestyksestä.
diff --git a/src/content/learn/queueing-a-series-of-state-updates.md b/src/content/learn/queueing-a-series-of-state-updates.md
index a63b7205b..a0986e09d 100644
--- a/src/content/learn/queueing-a-series-of-state-updates.md
+++ b/src/content/learn/queueing-a-series-of-state-updates.md
@@ -1,23 +1,23 @@
---
-title: Queueing a Series of State Updates
+title: Tilapäivitysten lisääminen jonoon
---
-Setting a state variable will queue another render. But sometimes you might want to perform multiple operations on the value before queueing the next render. To do this, it helps to understand how React batches state updates.
+Tilamuuttujan asettaminen lisää toisen renderöinnin jonoon. Toisinaan saatat haluta suorittaa useita operaatioita arvolla ennen seuraavan renderöinnin lisäämistä jonoon. Tätä varten on hyvä ymmärtää, miten React erittelee tilapäivitykset.
-* What "batching" is and how React uses it to process multiple state updates
-* How to apply several updates to the same state variable in a row
+* Mitä "niputtaminen" on ja kuinka React käyttää sitä prosessoidessaan useita tilapäivityksiä
+* Useiden päivitysten soveltaminen samaan tilamuuttujaan peräkkäin
-## React batches state updates {/*react-batches-state-updates*/}
+## React niputtaa tilapäivitykset {/*react-batches-state-updates*/}
-You might expect that clicking the "+3" button will increment the counter three times because it calls `setNumber(number + 1)` three times:
+Saatat olettaa, että painamalla "+3"-painiketta laskurin lukuu kasvaa kolme kertaa, koska se kutsuu `setNumber(number + 1)` kolmesti:
@@ -47,7 +47,7 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
-However, as you might recall from the previous section, [each render's state values are fixed](/learn/state-as-a-snapshot#rendering-takes-a-snapshot-in-time), so the value of `number` inside the first render's event handler is always `0`, no matter how many times you call `setNumber(1)`:
+Kuitenkin saatat muistaa edellisestä osasta, [kunkin renderin tila-arvot ovat kiinteät](/learn/state-as-a-snapshot#rendering-takes-a-snapshot-in-time), joten `number` muuttujan arvo ensimmäisen renderöinnin tapahtumakäsittelijässä on aina `0`, riippumatta siitä miten monesti kutsut `setNumber(1)` funktiota:
```js
setNumber(0 + 1);
@@ -55,21 +55,21 @@ setNumber(0 + 1);
setNumber(0 + 1);
```
-But there is one other factor at play here. **React waits until *all* code in the event handlers has run before processing your state updates.** This is why the re-render only happens *after* all these `setNumber()` calls.
+Mutta tässä on yksi toinen tekijä mukana pelissä. **React odottaa kunnes *kaikki* koodi tapahtumakäsittelijässä on suoritettu ennen tilapäivitysten laskentaa.** Tämän vuoksi uudelleen renderöinti tapahtuu kaikkien `setNumber()` kutsujen *jälkeen*.
-This might remind you of a waiter taking an order at the restaurant. A waiter doesn't run to the kitchen at the mention of your first dish! Instead, they let you finish your order, let you make changes to it, and even take orders from other people at the table.
+Tämä saattaa muistuttaa tarjoilijasta ottamassa tilauksia vastaan ravintolassa. Tarjoilija ei juokse keittiöön heti kun mainitset ensimmäisen aterian. Sen sijaan hän antaa sinun tehdä tilauksesi loppuun asti, tehdä siihen muutoksia ja sitten ottaa tilauksia vastaan muilta henkilöiltä pöydässä.
-This lets you update multiple state variables--even from multiple components--without triggering too many [re-renders.](/learn/render-and-commit#re-renders-when-state-updates) But this also means that the UI won't be updated until _after_ your event handler, and any code in it, completes. This behavior, also known as **batching,** makes your React app run much faster. It also avoids dealing with confusing "half-finished" renders where only some of the variables have been updated.
+Tämän avulla voit päivittää useita tilamuuttujia--jopa useista komponenteista--ilman ylimääräisten [renderöintien](/learn/render-and-commit#re-renders-when-state-updates) käynnistämistä. Tämä tarkoittaa kuitenkin myös sitä, että käyttöliittymä päivittyy vasta _jälkeen_, kun tapahtumankäsittelijäsi ja siinä oleva koodi on suoritettu. Tämä käyttäytyminen, joka tunnetaan myös nimellä **niputtaminen** (engl. batching), ja se saa React-sovelluksesi toimimaan paljon nopeammin. Sen avulla vältetään myös sekavat "puolivalmiit" renderöinnit, joissa vain osa muuttujista on päivitetty.
-**React does not batch across *multiple* intentional events like clicks**--each click is handled separately. Rest assured that React only does batching when it's generally safe to do. This ensures that, for example, if the first button click disables a form, the second click would not submit it again.
+**React ei niputa *useita* tarkoituksellisia tapahtumia kuten klikkauksia**--jokainen klikkaus käsitellään erikseen. Voit olla varma, että React tekee niputtamista vain silloin, kun se on yleisesti ottaen turvallista. Näin varmistetaan, että jos esimerkiksi ensimmäinen painikkeen napsautus poistaa lomakkeen käytöstä, toinen napsautus ei lähetä lomaketta uudelleen.
-## Updating the same state multiple times before the next render {/*updating-the-same-state-multiple-times-before-the-next-render*/}
+## Saman tilamuuttujan päivittäminen useita kertoja ennen seuraavaa renderöintiä {/*updating-the-same-state-multiple-times-before-the-next-render*/}
-It is an uncommon use case, but if you would like to update the same state variable multiple times before the next render, instead of passing the *next state value* like `setNumber(number + 1)`, you can pass a *function* that calculates the next state based on the previous one in the queue, like `setNumber(n => n + 1)`. It is a way to tell React to "do something with the state value" instead of just replacing it.
+Tämä on harvinainen käyttötapaus, mutta jos haluat päivittää saman tilamuuttujan useita kertoja ennen seuraavaa renderöintiä, sen sijaan, että välittäisit *seuraavan tilan arvon* kuten `setNumber(number + 1)`, voit välittää *funktion*, joka laskee seuraavan tilan jonon edellisen tilan perusteella, kuten `setNumber(n => n + 1)`. Se on tapa käskeä Reactia "tekemään jotain tila-arvolla" sen sijaan, että se vain korvaisi sen.
-Try incrementing the counter now:
+Kokeile kasvattaa laskuria nyt:
@@ -99,10 +99,10 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
-Here, `n => n + 1` is called an **updater function.** When you pass it to a state setter:
+Tässä, `n => n + 1` on**päivitysfunktio.** Kun välität sen tila-asettajalle:
-1. React queues this function to be processed after all the other code in the event handler has run.
-2. During the next render, React goes through the queue and gives you the final updated state.
+1. React lisää tämän funktion jonoon prosessoitavaksi kun kaikki muut koodi tapahtumakäsittelijässä on suoritettu.
+2. Seuraavan renderöinnin aikana React käy jonon läpi ja antaa sinulle lopullisen päivitetyn tilan.
```js
setNumber(n => n + 1);
@@ -110,26 +110,26 @@ setNumber(n => n + 1);
setNumber(n => n + 1);
```
-Here's how React works through these lines of code while executing the event handler:
+Näin React käy läpi nämä rivit koodia tapahtumakäsittelijää suoritettaessa:
-1. `setNumber(n => n + 1)`: `n => n + 1` is a function. React adds it to a queue.
-1. `setNumber(n => n + 1)`: `n => n + 1` is a function. React adds it to a queue.
-1. `setNumber(n => n + 1)`: `n => n + 1` is a function. React adds it to a queue.
+1. `setNumber(n => n + 1)`: `n => n + 1` on funktio. React lisää sen jonoon.
+1. `setNumber(n => n + 1)`: `n => n + 1` on funktio. React lisää sen jonoon.
+1. `setNumber(n => n + 1)`: `n => n + 1` on funktio. React lisää sen jonoon.
-When you call `useState` during the next render, React goes through the queue. The previous `number` state was `0`, so that's what React passes to the first updater function as the `n` argument. Then React takes the return value of your previous updater function and passes it to the next updater as `n`, and so on:
+Kun kutsut `useState` funktiota renderöinnin aikana, React käy jonon läpi. Edellinen `number`:n tila oli `0`, joten React välittää sen ensimmäiselle päivitysfunktiolle argumenttina `n`. Sitten React ottaa edellisen päivitysfunktion paluuarvon ja siirtää sen seuraavalle päivitysfunktiolle `n` muuttujana, ja niin edelleen:
-| queued update | `n` | returns |
+| päivitys jonossa | `n` | palauttaa |
|--------------|---------|-----|
| `n => n + 1` | `0` | `0 + 1 = 1` |
| `n => n + 1` | `1` | `1 + 1 = 2` |
| `n => n + 1` | `2` | `2 + 1 = 3` |
-React stores `3` as the final result and returns it from `useState`.
+React tallentaa `3` lopulliseksi tulokseksi ja palauttaa sen `useState`:sta.
-This is why clicking "+3" in the above example correctly increments the value by 3.
-### What happens if you update state after replacing it {/*what-happens-if-you-update-state-after-replacing-it*/}
+Tämän vuoksi napsauttamalla "+3" yllä olevassa esimerkissä arvo kasvaa oikein 3:lla.
+### Mitä tapahtuu, jos päivität tilan sen korvaamisen jälkeen? {/*what-happens-if-you-update-state-after-replacing-it*/}
-What about this event handler? What do you think `number` will be in the next render?
+Entä tämä tapahtumankäsittelijä? Mitä luulet, että `number` on seuraavassa renderöinnissä?
```js
{
@@ -165,29 +165,29 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
-Here's what this event handler tells React to do:
+Tämä tapahtumankäsittelijä käskee Reactia tekemään seuraavaa:
-1. `setNumber(number + 5)`: `number` is `0`, so `setNumber(0 + 5)`. React adds *"replace with `5`"* to its queue.
-2. `setNumber(n => n + 1)`: `n => n + 1` is an updater function. React adds *that function* to its queue.
+1. `setNumber(number + 5)`: `number` on `0`, joten `setNumber(0 + 5)`. React lisää *"korvaa arvolla `5`"* sen jonoon.
+2. `setNumber(n => n + 1)`: `n => n + 1` on päivitysfunktio. React lisää *tuon funktion* sen jonoon.
-During the next render, React goes through the state queue:
+Seuraavan renderöinnin aikana React käy läpi tilajonon:
-| queued update | `n` | returns |
+| päivitys jonossa | `n` | palauttaa |
|--------------|---------|-----|
-| "replace with `5`" | `0` (unused) | `5` |
+| "replace with `5`" | `0` (käyttämätön) | `5` |
| `n => n + 1` | `5` | `5 + 1 = 6` |
-React stores `6` as the final result and returns it from `useState`.
+React tallentaa `6` lopulliseksi tulokseksi ja palauttaa sen `useState`:sta.
-You may have noticed that `setState(5)` actually works like `setState(n => 5)`, but `n` is unused!
+Olet ehkä huomannut, että `setState(5)` toimii kuten `setState(n => 5)`, mutta `n` on käyttämätön!
-### What happens if you replace state after updating it {/*what-happens-if-you-replace-state-after-updating-it*/}
+### Mitä tapahtuu, jos korvaat tilan sen päivittämisen jälkeen? {/*what-happens-if-you-replace-state-after-updating-it*/}
-Let's try one more example. What do you think `number` will be in the next render?
+Kokeillaan vielä yhtä esimerkkiä. Mitä luulet, että `number` on seuraavassa renderöinnissä?
```js
{
@@ -225,32 +225,32 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
-Here's how React works through these lines of code while executing this event handler:
+Näin React käy läpi nämä rivit koodia tapahtumakäsittelijää suoritettaessa:
-1. `setNumber(number + 5)`: `number` is `0`, so `setNumber(0 + 5)`. React adds *"replace with `5`"* to its queue.
-2. `setNumber(n => n + 1)`: `n => n + 1` is an updater function. React adds *that function* to its queue.
-3. `setNumber(42)`: React adds *"replace with `42`"* to its queue.
+1. `setNumber(number + 5)`: `number` on `0`, joten `setNumber(0 + 5)`. React lisää *"korvaa arvolla `5`"* sen jonoon.
+2. `setNumber(n => n + 1)`: `n => n + 1` on päivitysfunktio. React lisää *tuon funktion* sen jonoon.
+3. `setNumber(42)`: React lisää *"korvaa arvolla `42`"* sen jonoon.
-During the next render, React goes through the state queue:
+Seuraavan renderöinnin aikana React käy läpi tilajonon:
-| queued update | `n` | returns |
+| päivitys jonossa | `n` | palauttaa |
|--------------|---------|-----|
-| "replace with `5`" | `0` (unused) | `5` |
+| "korvaa arvolla `5`" | `0` (käyttämätön) | `5` |
| `n => n + 1` | `5` | `5 + 1 = 6` |
-| "replace with `42`" | `6` (unused) | `42` |
+| "korvaa arvolla `42`" | `6` (käyttämätön) | `42` |
-Then React stores `42` as the final result and returns it from `useState`.
+Sitten React tallentaa `42` lopulliseksi tulokseksi ja palauttaa sen `useState`:sta.
-To summarize, here's how you can think of what you're passing to the `setNumber` state setter:
+Yhteenvetona voit ajatella näin, mitä välität `setNumber` tila-asettimeen:
-* **An updater function** (e.g. `n => n + 1`) gets added to the queue.
-* **Any other value** (e.g. number `5`) adds "replace with `5`" to the queue, ignoring what's already queued.
+* **Päivitysfunktion** (esim. `n => n + 1`) lisätään jonoon.
+* **Minkä tahansa arvon** (esim. numero `5`) lisää "korvaa arvolla `5`" jonoon, huomioimatta sitä, mikä on jo jonossa.
-After the event handler completes, React will trigger a re-render. During the re-render, React will process the queue. Updater functions run during rendering, so **updater functions must be [pure](/learn/keeping-components-pure)** and only *return* the result. Don't try to set state from inside of them or run other side effects. In Strict Mode, React will run each updater function twice (but discard the second result) to help you find mistakes.
+Tapahtumankäsittelijän päätyttyä React käynnistää uuden renderöinnin. Uudelleen renderöinnin aikana React käsittelee jonon. Päivitysfunktiot suoritetaan renderöinnin aikana, joten **päivitysfunktioiden on oltava [puhtaita](/learn/keeping-components-pure)** ja *palauttavat* vain tuloksen. Älä yritä asettaa tilaa niiden sisältä tai suorittaa muita sivuvaikutuksia. Strict Modessa, React suorittaa jokaisen päivitysfunktion kahdesti (mutta hylkää toisen tuloksen) auttaakseen sinua löytämään virheitä.
-### Naming conventions {/*naming-conventions*/}
+### Nimeämiskäytännöt {/*naming-conventions*/}
-It's common to name the updater function argument by the first letters of the corresponding state variable:
+On tavallista nimetä päivitysfunktion argumentti vastaavan tilamuuttujan alkukirjaimilla:
```js
setEnabled(e => !e);
@@ -258,13 +258,13 @@ setLastName(ln => ln.reverse());
setFriendCount(fc => fc * 2);
```
-If you prefer more verbose code, another common convention is to repeat the full state variable name, like `setEnabled(enabled => !enabled)`, or to use a prefix like `setEnabled(prevEnabled => !prevEnabled)`.
+Jos haluat yksityiskohtaisempaa koodia, toinen yleinen käytäntö on toistaa koko tilamuuttujan nimi, kuten `setEnabled(enabled => !enabled)`, tai käyttää etuliitettä kuten `setEnabled(prevEnabled => !prevEnabled)`.
-* Setting state does not change the variable in the existing render, but it requests a new render.
-* React processes state updates after event handlers have finished running. This is called batching.
-* To update some state multiple times in one event, you can use `setNumber(n => n + 1)` updater function.
+* Tilan asettaminen ei muuta tilamuuttujaa olemassa olevassa renderöinnissä, vaan pyytää uutta renderöintiä.
+* React käsittelee tilapäivitykset sen jälkeen, kun tapahtumakäsittelijät ovat lopettaneet suorituksensa. Tätä kutsutaan niputtamiseksi.
+* Jos haluat päivittää jonkin tilan useita kertoja yhdessä tapahtumassa, voit käyttää `setNumber(n => n + 1)`-päivitysfunktiota.
@@ -272,13 +272,13 @@ If you prefer more verbose code, another common convention is to repeat the full
-#### Fix a request counter {/*fix-a-request-counter*/}
+#### Korjaa pyyntöjen laskuri {/*fix-a-request-counter*/}
-You're working on an art marketplace app that lets the user submit multiple orders for an art item at the same time. Each time the user presses the "Buy" button, the "Pending" counter should increase by one. After three seconds, the "Pending" counter should decrease, and the "Completed" counter should increase.
+Olet kehittämässä taiteen markkinapaikkasovellusta, jonka avulla käyttäjä voi tehdä useita tilauksia taide-esineestä samanaikaisesti. Joka kertan, kun käyttäjä painaa "Osta"-painiketta, "Vireillä"-laskurin pitäisi kasvaa yhdellä. Kolmen sekuntin kuluttua "Vireillä"-laskurin pitäisi pienentyä ja "Toteutunut" laskurin pitäisi kasvaaa.
-However, the "Pending" counter does not behave as intended. When you press "Buy", it decreases to `-1` (which should not be possible!). And if you click fast twice, both counters seem to behave unpredictably.
+Vireillä -laskuri ei kuitenkaan käyttäydy tarkoitetulla tavalla. Kun painat "Osta", se laskee arvoon `-1` (minkä ei pitäisi olla mahdollista!). Ja jos painat nopeasti kahdesti, molemmat laskurit näyttävät käyttäytyvän arvaamattomasti.
-Why does this happen? Fix both counters.
+Miksi näin tapahtuu? Korjaa molemmat laskurit.
@@ -299,13 +299,13 @@ export default function RequestTracker() {
return (
<>
- Pending: {pending}
+ Vireillä: {pending}
- Completed: {completed}
+ Toteutunut: {completed}
- Buy
+ Osta
>
);
@@ -322,7 +322,7 @@ function delay(ms) {
-Inside the `handleClick` event handler, the values of `pending` and `completed` correspond to what they were at the time of the click event. For the first render, `pending` was `0`, so `setPending(pending - 1)` becomes `setPending(-1)`, which is wrong. Since you want to *increment* or *decrement* the counters, rather than set them to a concrete value determined during the click, you can instead pass the updater functions:
+`handleClick`-tapahtumankäsittelijän sisällä `pending` ja `completed` arvot vastaavat arvoja, jotka ne olivat klikkaustapahtuman aikaan. Ensimmäisessä renderöinnissä `pending` oli `0`, joten `setPending(pending - 1)` muuttuu `setPending(-1)`, mikä on väärin. Koska haluat *kasvattaa* tai *vähentää* laskureita sen sijaan, että asettaisit ne klikkauksen aikana määritettyyn konkreettiseen arvoon, voit sen sijaan välittää niille päivitysfunktiot:
@@ -364,23 +364,23 @@ function delay(ms) {
-This ensures that when you increment or decrement a counter, you do it in relation to its *latest* state rather than what the state was at the time of the click.
+Näin varmistetaan, että kun kasvatat tai vähennät laskuria, se tehdään suhteessa sen *viimeisimpään* tilaan eikä siihen, mikä tila oli napsautushetkellä.
-#### Implement the state queue yourself {/*implement-the-state-queue-yourself*/}
+#### Toteuta tilajono itse {/*implement-the-state-queue-yourself*/}
-In this challenge, you will reimplement a tiny part of React from scratch! It's not as hard as it sounds.
+Tässä haasteessa toteutat pienen osan Reactista alusta alkaen! Se ei ole niin vaikeaa kuin miltä se kuulostaa.
-Scroll through the sandbox preview. Notice that it shows **four test cases.** They correspond to the examples you've seen earlier on this page. Your task is to implement the `getFinalState` function so that it returns the correct result for each of those cases. If you implement it correctly, all four tests should pass.
+Selaa hiekkalaatikon esikatselua. Huomaa, että siinä näkyy **neljä testitapausta.** Ne vastaavat aiemmin tällä sivulla näkemiäsi esimerkkejä. Tehtävänäsi on toteuttaa `getFinalState`-funktio niin, että se palauttaa oikean tuloksen jokaisessa näistä tapauksista. Jos toteutat sen oikein, kaikkien neljän testin pitäisi mennä läpi.
-You will receive two arguments: `baseState` is the initial state (like `0`), and the `queue` is an array which contains a mix of numbers (like `5`) and updater functions (like `n => n + 1`) in the order they were added.
+Saat kaksi argumenttia: `baseState` on aloitustila, joka sisältää numeroita (kuten `0`) ja `queue`, joka on taulukko, joka sisältää sekoituksen numeroita (kuten `5`) ja päivitysfunktioita (kuten `n => n + 1`) siinä järjestyksessä kuin ne on lisätty.
-Your task is to return the final state, just like the tables on this page show!
+Tehtäväsi on palauttaa lopullinen tila, aivan kuten tämän sivun taulukot osoittavat!
-If you're feeling stuck, start with this code structure:
+Jos tunnet olevasi jumissa, aloita tästä koodirakenteesta:
```js
export function getFinalState(baseState, queue) {
@@ -398,7 +398,7 @@ export function getFinalState(baseState, queue) {
}
```
-Fill out the missing lines!
+Täytä puuttuvat rivit!
@@ -495,7 +495,7 @@ function TestCase({
-This is the exact algorithm described on this page that React uses to calculate the final state:
+Tämä on täsmälleen tällä sivulla kuvattu algoritmi, jota React käyttää lopullisen tilan laskemiseen:
@@ -596,7 +596,7 @@ function TestCase({
-Now you know how this part of React works!
+Nyt tiedät, miten tämä osa Reactia toimii!
diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md
index 89208a6bb..a001f8708 100644
--- a/src/content/learn/react-developer-tools.md
+++ b/src/content/learn/react-developer-tools.md
@@ -1,33 +1,34 @@
---
-title: React Developer Tools
+title: React kehitystyökalut
---
-Use React Developer Tools to inspect React [components](/learn/your-first-component), edit [props](/learn/passing-props-to-a-component) and [state](/learn/state-a-components-memory), and identify performance problems.
+React kehitystyökaluja voi käyttää tarkastamaan React [komponentteja](/learn/your-first-component), muokkaamaan [propseja](/learn/passing-props-to-a-component) ja [tilaa](/learn/state-a-components-memory) sekä tunnistamaan suorityskykyongelmia.
-* How to install React Developer Tools
+* Miten asennetaan React kehitystyökalut
-## Browser extension {/*browser-extension*/}
+## Selainlisäosa {/*browser-extension*/}
-The easiest way to debug websites built with React is to install the React Developer Tools browser extension. It is available for several popular browsers:
+Helpoin tapa debugata Reactilla rakennettuja verkkosivuja on asentamalla React Developer Tools selainlisäosa. Se on saatavilla useille suosituille selaimille:
-* [Install for **Chrome**](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)
-* [Install for **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/)
-* [Install for **Edge**](https://microsoftedge.microsoft.com/addons/detail/react-developer-tools/gpphkfbcpidddadnkolkpfckpihlkkil)
+* [Asenna **Chrome** selaimeen](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en)
+* [Asenna **Firefox** selaimeen](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/)
+* [Asenna **Edge** selaimeen](https://microsoftedge.microsoft.com/addons/detail/react-developer-tools/gpphkfbcpidddadnkolkpfckpihlkkil)
-Now, if you visit a website **built with React,** you will see the _Components_ and _Profiler_ panels.
+Nyt jos vierailet **Reactilla rakennetulla** verkkosivulla, näet _Components_ ja _Profile_ välilehdet.
-
+
-### Safari and other browsers {/*safari-and-other-browsers*/}
-For other browsers (for example, Safari), install the [`react-devtools`](https://www.npmjs.com/package/react-devtools) npm package:
+### Safari ja muut selaimet {/*safari-and-other-browsers*/}
+
+Muille selaimille (kuten esimerkiksi, Safarille), asenna [`react-devtools`](https://www.npmjs.com/package/react-devtools) npm lisäosa:
```bash
# Yarn
yarn global add react-devtools
@@ -36,26 +37,27 @@ yarn global add react-devtools
npm install -g react-devtools
```
-Next open the developer tools from the terminal:
+Seuraavaksi avaa kehitystyökalut terminaalista:
```bash
react-devtools
```
-Then connect your website by adding the following `
```
-Reload your website in the browser now to view it in developer tools.
+Lataa sivu uudelleen selaimessa näähdäksesi sen kehitystyökalussa.
+
+
-
+## Mobiili (React Native) {/*mobile-react-native*/}
-## Mobile (React Native) {/*mobile-react-native*/}
-React Developer Tools can be used to inspect apps built with [React Native](https://reactnative.dev/) as well.
+React kehistystyökalulla voidaan katsoa myöskin [React Native](https://reactnative.dev/):lla rakennettuja sovelluksia.
-The easiest way to use React Developer Tools is to install it globally:
+Helpoin tapa käyttää React kehitystyökaluja on asentamalla se globaalisti:
```bash
# Yarn
yarn global add react-devtools
@@ -64,13 +66,13 @@ yarn global add react-devtools
npm install -g react-devtools
```
-Next open the developer tools from the terminal.
+Sitten avaa kehitystyökalut terminaalista.
```bash
react-devtools
```
-It should connect to any local React Native app that's running.
+Sen pitäisi yhdistää mihin tahansa paikalliseen, käynnissäolevaan React Native sovellukseen.
-> Try reloading the app if developer tools doesn't connect after a few seconds.
+> Kokeile käynnistää sovellus uudelleen mikäli kehitystyökalu ei yhdistä muutaman sekuntin kuluttua.
-[Learn more about debugging React Native.](https://reactnative.dev/docs/debugging)
+[Lue lisää React Nativen debuggaamisesta.](https://reactnative.dev/docs/debugging)
diff --git a/src/content/learn/reacting-to-input-with-state.md b/src/content/learn/reacting-to-input-with-state.md
index 522aa63a1..6841cd941 100644
--- a/src/content/learn/reacting-to-input-with-state.md
+++ b/src/content/learn/reacting-to-input-with-state.md
@@ -1,37 +1,37 @@
---
-title: Reacting to Input with State
+title: Reagointi syötteen tilaan
---
-React provides a declarative way to manipulate the UI. Instead of manipulating individual pieces of the UI directly, you describe the different states that your component can be in, and switch between them in response to the user input. This is similar to how designers think about the UI.
+React tarjoaa deklaratiivisen tavan käsitellä käyttöliittymää. Sen sijaan, että manipuloisit suoraan käyttöliittymän yksittäisiä osia, määrittelet eri tilat, joissa komponenttisi voi olla, ja vaihdat niiden välillä käyttäjän syötteen perusteella. Tämä muistuttaa sitä, miten suunnittelijat ajattelevat käyttöliittymästä.
-* How declarative UI programming differs from imperative UI programming
-* How to enumerate the different visual states your component can be in
-* How to trigger the changes between the different visual states from code
+* Miten deklaratiiviinen käyttöliittymäohjelmointi eroaa imperatiivisesta käyttöliittymäohjelmoinnista
+* Kuinka luetella eri visuaaliset tilat, joissa komponenttisi voi olla?
+* Miten käynnistää muutokset eri visuaalisten tilojen välillä koodista käsin?
-## How declarative UI compares to imperative {/*how-declarative-ui-compares-to-imperative*/}
+## Miten deklaratiivinen käyttöliittymä vertautuu imperatiiviseen {/*how-declarative-ui-compares-to-imperative*/}
-When you design UI interactions, you probably think about how the UI *changes* in response to user actions. Consider a form that lets the user submit an answer:
+Kun suunnittelet käyttöliittymän vuorovaikutusta, luultavasti mietit, miten käyttöliittymä *muuttuu* käyttäjän toimien seurauksena. Ajattele lomaketta, jonka avulla käyttäjä voi lähettää vastauksen:
-* When you type something into the form, the "Submit" button **becomes enabled.**
-* When you press "Submit", both the form and the button **become disabled,** and a spinner **appears.**
-* If the network request succeeds, the form **gets hidden,** and the "Thank you" message **appears.**
-* If the network request fails, an error message **appears,** and the form **becomes enabled** again.
+* Kun kirjoitat jotain lomakkeeseen, "Lähetä" painike **tulee käyttöön.**
+* Kun painat "Lähetä", sekä lomake että painike **poistuu käytöstä,** ja latausikoni **tulee näkyviin.**
+* Jos verkkopyyntö onnistuu, lomake **piiloutuu,** ja "Kiitos" viesti **tulee näkyviin.**
+* Jos verkkopyyntö epäonnistuu, virheviesti **tulee näkyviin,** ja lomake **tulee käyttöön** uudelleen.
-In **imperative programming,** the above corresponds directly to how you implement interaction. You have to write the exact instructions to manipulate the UI depending on what just happened. Here's another way to think about this: imagine riding next to someone in a car and telling them turn by turn where to go.
+**Imperatiivisessa ohjelmoinnissa,** edellä mainittu viittaa suoraan siihen miten vuorovaikutus toteutetaan. Sinun täytyy kirjoittaa tarkat ohjeet käyttöliittymän manipulointiin sen perusteella mitä juuri tapahtui. Toinen tapa ajatella tätä on: Kuvittele, että olet autossa jonkun vieressä ja kerrot hänelle mihin käännytään joka käännökseltä.
-
+
-They don't know where you want to go, they just follow your commands. (And if you get the directions wrong, you end up in the wrong place!) It's called *imperative* because you have to "command" each element, from the spinner to the button, telling the computer *how* to update the UI.
+Hän ei tiedä mihin haluat mennä, noudattavat vain käskyjäsi. (Ja jos annat vääriä ohjeita, päädyt väärään paikkaan!) Tätä kutsutaan *imperatiiviseksi*, koska jokaista elementtiä täytyy "käskeä", latausikonista painikkeeseen, kertoen tietokoneelle *miten* päivittää käyttöliittymää.
-In this example of imperative UI programming, the form is built *without* React. It only uses the browser [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model):
+Tässä imperatiivisen käyttöliittymäohjelmoinnin esimerkissä lomake on rakennettu *ilman* Reactia. Se käyttää vain selaimen sisäänrakennettua [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model):a.
@@ -81,7 +81,7 @@ function disable(el) {
}
function submitForm(answer) {
- // Pretend it's hitting the network.
+ // Oletetaan, että se yhdistäisi verkkoon.
return new Promise((resolve, reject) => {
setTimeout(() => {
if (answer.toLowerCase() == 'istanbul') {
@@ -131,37 +131,37 @@ body { font-family: sans-serif; margin: 20px; padding: 0; }
-Manipulating the UI imperatively works well enough for isolated examples, but it gets exponentially more difficult to manage in more complex systems. Imagine updating a page full of different forms like this one. Adding a new UI element or a new interaction would require carefully checking all existing code to make sure you haven't introduced a bug (for example, forgetting to show or hide something).
+Käyttöliittymän manipulointi imperatiivisesti toimii hyvin eristetyissä esimerkeissä, mutta siitä tulee eksponentiaalisesti hankalempaa hallita monimutkaisissa järjestelmissä. Kuvittele, että päivität sivua täynnä erilaisia lomakkeita kuten tämä. Uuden käyttöliittymäelementin tai vuorovaikutuksen lisääminen vaatisi huolellista koodin tarkistusta, ettet ole luonut bugia (esimerkiksi, unohtanut näyttää tai piilottaa jotain).
-React was built to solve this problem.
+React on rakennettu ratkaisemaan tämä ongelma.
-In React, you don't directly manipulate the UI--meaning you don't enable, disable, show, or hide components directly. Instead, you **declare what you want to show,** and React figures out how to update the UI. Think of getting into a taxi and telling the driver where you want to go instead of telling them exactly where to turn. It's the driver's job to get you there, and they might even know some shortcuts you haven't considered!
+Reactissa et suoraan manipuloi käyttöliittymää--tarkoittaen, että et ota käyttöön, poista käytöstä, näytä/piilota komponentteja suoraan. Sen sijaan **määrittelet mitä haluat näyttää,** ja React päättelee miten käyttöliittymä päivitetään. Kuvittele olevasi taksissa ja kerrot kuskille mihin haluat mennä sen sijaan, että kertoisit mihin kääntyä. On kuskin tehtävä viedä sinut sinne ja hän saattaa jopa tietää joitain oikoteita, joita et ole saattanut ottaa huomioon!
-
+
-## Thinking about UI declaratively {/*thinking-about-ui-declaratively*/}
+## Käyttöliittymän ajatteleminen deklaratiivisesti {/*thinking-about-ui-declaratively*/}
-You've seen how to implement a form imperatively above. To better understand how to think in React, you'll walk through reimplementing this UI in React below:
+Nyt olet nähnyt ylhäällä miten lomake toteutetaan imperatiivisesti. Jotta ymmärtäisit paremmin, miten Reactissa ajatellaan, käydään alla läpi tämän käyttöliittymän uudelleen toteuttaminen Reactissa:
-1. **Identify** your component's different visual states
-2. **Determine** what triggers those state changes
-3. **Represent** the state in memory using `useState`
-4. **Remove** any non-essential state variables
-5. **Connect** the event handlers to set the state
+1. **Tunnista** komponenttisi eri visuaaliset tilat
+2. **Määritä** mikä käynnistää nämä tilamuutokset
+3. **Edusta** tila muistissa käyttäen `useState` hookkia
+4. **Poista** kaikki epäolennaiset tilamuuttujat
+5. **Yhdistä** tapahtumakäsittelijät tilan asettamiseksi
-### Step 1: Identify your component's different visual states {/*step-1-identify-your-components-different-visual-states*/}
+### 1. Vaihe: Tunnista komponenttisi eri visuaaliset tilat {/*step-1-identify-your-components-different-visual-states*/}
-In computer science, you may hear about a ["state machine"](https://en.wikipedia.org/wiki/Finite-state_machine) being in one of several “states”. If you work with a designer, you may have seen mockups for different "visual states". React stands at the intersection of design and computer science, so both of these ideas are sources of inspiration.
+Tietojenkäsittelytieteessä olet saattanut kuulla ["tilakoneesta"](https://en.wikipedia.org/wiki/Finite-state_machine), joka voi olla yhdessä useista "tiloista". Jos työskentelet suunnittelijan kanssa, olet saattanut nähdä mallinnuksia erilaisista "visuaalisista tiloista". React on suunnittelun ja tietotekniikan risteyskohta, joten molemmat ideat ovat inspiraation lähteitä.
-First, you need to visualize all the different "states" of the UI the user might see:
+Ensiksi, täytyy visualisoida kaikki käyttöliittymän eri "tilat", joita käyttäjä saattaa nähdä:
-* **Empty**: Form has a disabled "Submit" button.
-* **Typing**: Form has an enabled "Submit" button.
-* **Submitting**: Form is completely disabled. Spinner is shown.
-* **Success**: "Thank you" message is shown instead of a form.
-* **Error**: Same as Typing state, but with an extra error message.
+* **Tyhjä**: Lomakkeen "Lähetä" painike on poissa käytöstä.
+* **Kirjoittaa**: Lomakkeen "Lähetä" painike on käytössä.
+* **Lähettää**: Lomake on kokonaan poissa käytöstä. Latausikoni näkyy.
+* **Onnistui**: "Kiitos" viesti näkyy lomakkeen sijaan.
+* **Virhe**: Sama kuin Kirjoittaa -tila, mutta lisävirheviestillä.
-Just like a designer, you'll want to "mock up" or create "mocks" for the different states before you add logic. For example, here is a mock for just the visual part of the form. This mock is controlled by a prop called `status` with a default value of `'empty'`:
+Juuri kuten suunnittelija haluat "mallintaa" tai luoda "malleja" eri tiloihin ennen kuin lisäät logiikkaa. Esimerkiksi, tässä on malli vain lomakkeen visuaaliselle osalle. Tämä malli ohjataan `status` propsin kautta, jonka oletusarvona on `'empty'`:
@@ -192,7 +192,7 @@ export default function Form({
-You could call that prop anything you like, the naming is not important. Try editing `status = 'empty'` to `status = 'success'` to see the success message appear. Mocking lets you quickly iterate on the UI before you wire up any logic. Here is a more fleshed out prototype of the same component, still "controlled" by the `status` prop:
+Voisit nimetä propsin miten haluat, nimi ei nyt ole niin tärkeää. Kokeile muokata propsi `status = 'empty'` arvoon `status = 'success'` nähdäksesi onnistumisviestin. Mallintamisen avulla voit nopeasti iteroida käyttöliittymää ennen kuin lisäät logiikkaa. Tässä on täyteläisempi prototyyppi samasta komponentista, joka silti ohjataan `status` propsilla:
@@ -240,9 +240,9 @@ export default function Form({
-#### Displaying many visual states at once {/*displaying-many-visual-states-at-once*/}
+#### Monien visuaalisten tilojen näyttäminen kerralla {/*displaying-many-visual-states-at-once*/}
-If a component has a lot of visual states, it can be convenient to show them all on one page:
+Jos komponentilla on monia visuaalisia tiloja, voi olla kätevää näyttää ne kaikki samalla sivulla:
@@ -307,61 +307,59 @@ body { margin: 0; }
-Pages like this are often called "living styleguides" or "storybooks".
+Tämänkaltaisia sivuja usein kutsutaan "eläviksi tyyliohjeiksi" tai "storybookeiksi".
-### Step 2: Determine what triggers those state changes {/*step-2-determine-what-triggers-those-state-changes*/}
+### 2. Vaihe: Määritä, mikä laukaisee nämä tilamuutokset {/*step-2-determine-what-triggers-those-state-changes*/}
-You can trigger state updates in response to two kinds of inputs:
+Voit käynnistää tilamuutoksen vastauksena kahdenlaiseen syötteeseen:
-* **Human inputs,** like clicking a button, typing in a field, navigating a link.
-* **Computer inputs,** like a network response arriving, a timeout completing, an image loading.
+* **Ihmisen syötteeseen,** kuten painikeen klikkaaminen, tekstin kirjoittaminen, linkkiin navigoiminen.
+* **Tietokoneen syötteeseen,** kuten verkkopyynnön vastauksen saapuminen, aikakatkaisun päättyminen, kuvan lataaminen.
-
-
+
+
-In both cases, **you must set [state variables](/learn/state-a-components-memory#anatomy-of-usestate) to update the UI.** For the form you're developing, you will need to change state in response to a few different inputs:
+Molemmissa tapauksissa, **saatat asettaa [tilamuuttujia](/learn/state-a-components-memory#anatomy-of-usestate) käyttöliittymän päivittämiseksi.** Kehittämässäsi lomakkeessa sinun on vaihdettava tilaa muutaman eri syötteen perusteella:
-* **Changing the text input** (human) should switch it from the *Empty* state to the *Typing* state or back, depending on whether the text box is empty or not.
-* **Clicking the Submit button** (human) should switch it to the *Submitting* state.
-* **Successful network response** (computer) should switch it to the *Success* state.
-* **Failed network response** (computer) should switch it to the *Error* state with the matching error message.
+* **Tekstinsyötön muuttaminen** (ihminen) tulisi muuttaa *Tyhjä* tila *Kirjoitetaan* -tilaan tai päin vastoin, riippuen siitä onko syöttökenttä tyhjä vai ei.
+* **Lähetä -painikkeen klikkaaminen** (ihminen) tulisi muuttaa tila *Lähetetään* arvoon.
+* **Onnistunut verkkovastaus** (tietokone) tulisi muuttaa tila *Onnistunut* arvoon.
+* **Epäonnistunut verkkovastaus** (tietokone) tulisi muuttaa tila *Virhe* arvoon itse virheviestin kanssa.
-Notice that human inputs often require [event handlers](/learn/responding-to-events)!
+Huomaa, että ihmisen syötteet usein vaativat [tapahtumakäsittelijöitä](/learn/responding-to-events)!
-To help visualize this flow, try drawing each state on paper as a labeled circle, and each change between two states as an arrow. You can sketch out many flows this way and sort out bugs long before implementation.
+Ymmärtääksesi tämän prosessin paremmin voit kokeilla piirtää paperille jokaisen tilan ympyräksi ja jokaisen tilamuutoksen nuolina. Voit hahmotella monia prosesseja tällä tavoin ja selvittää virheet kauan ennen toteutusta.
-
+
-Form states
+Lomakkeen tilat
-### Step 3: Represent the state in memory with `useState` {/*step-3-represent-the-state-in-memory-with-usestate*/}
+### 3. Vaihe: Esitä tila muistissa käyttämällä `useState`:a {/*step-3-represent-the-state-in-memory-with-usestate*/}
-Next you'll need to represent the visual states of your component in memory with [`useState`.](/reference/react/useState) Simplicity is key: each piece of state is a "moving piece", and **you want as few "moving pieces" as possible.** More complexity leads to more bugs!
+Seuraavaksi sinun täytyy esitellä komponenttisi visuaaliset tilat muistissa [`useState`.](/reference/react/useState) hookilla. Yksinkertaisuus on avainasemassa: jokainen osa tilaa on "liikkuva osa", ja **haluat niin vähän "liikkuvia osia" kuin mahdollista.** Suurempi monimutkaisuus johtaa useampiin virheisiin!
-Start with the state that *absolutely must* be there. For example, you'll need to store the `answer` for the input, and the `error` (if it exists) to store the last error:
+Aloita tilalla, jonka on *ehdottomasti oltava* siellä. Sinun on esimerkiksi tallennettava `answer` syötettä varten ja `error` (jos se on olemassa) viimeisimmän virheen tallentamiseksi:
```js
const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
```
-Then, you'll need a state variable representing which one of the visual states that you want to display. There's usually more than a single way to represent that in memory, so you'll need to experiment with it.
-
-If you struggle to think of the best way immediately, start by adding enough state that you're *definitely* sure that all the possible visual states are covered:
+Sitten tarvitset tilamuuttujan, joka kuvaa, minkä aiemmin kuvatuista visuaalisista tiloista haluat näyttää. Muistissa on yleensä useampi kuin yksi tapa esittää tämä, joten sinun täytyy kokeilla sitä.
```js
const [isEmpty, setIsEmpty] = useState(true);
@@ -370,40 +368,38 @@ const [isSubmitting, setIsSubmitting] = useState(false);
const [isSuccess, setIsSuccess] = useState(false);
const [isError, setIsError] = useState(false);
```
+Ensimmäinen ideasi ei todennäköisesti ole paras mahdollinen, mutta se ei haittaa - tilan muokkaaminen on osa prosessia!
-Your first idea likely won't be the best, but that's ok--refactoring state is a part of the process!
+### 4. Vaihe: Poista kaikki epäolennaiset tilamuuttujat {/*step-4-remove-any-non-essential-state-variables*/}
-### Step 4: Remove any non-essential state variables {/*step-4-remove-any-non-essential-state-variables*/}
+Haluat välttää toistoa tilasisällössä, jotta seuraat vain olennaisia asioita. Jos käytät hieman aikaa tilarakenteesi uudistamiseen, komponenttisi ovat helpommin ymmärrettävissä, toistoa vähennetään ja tahattomia merkityksiä vältetään. Tavoitteenasi on **estää tapaukset, joissa muistissa oleva tila ei edusta mitään pätevää käyttöliittymää, jonka haluaisit käyttäjän näkevän.** (Et esimerkiksi koskaan halua näyttää virheilmoitusta ja poistaa syötettä käytöstä samaan aikaan, tai käyttäjä ei pysty korjaamaan virhettä!).
-You want to avoid duplication in the state content so you're only tracking what is essential. Spending a little time on refactoring your state structure will make your components easier to understand, reduce duplication, and avoid unintended meanings. Your goal is to **prevent the cases where the state in memory doesn't represent any valid UI that you'd want a user to see.** (For example, you never want to show an error message and disable the input at the same time, or the user won't be able to correct the error!)
+Tässä on joitakin kysymyksiä, joita voit kysyä tilamuuttujiltasi:
-Here are some questions you can ask about your state variables:
+* **Aiheuttaako tämä tila paradoksin?** Esimerkiksi, `isTyping` ja `isSubmitting` eivät voi molemmat olla arvoltaan `true`. Paradoksi tarkoittaa yleensä sitä, että tilaa ei ole tarpeeksi rajattu. Kahden totuusarvon yhdistelmiä voi olla neljä, mutta vain kolme vastaa kelvollisia tiloja. Jos haluat poistaa "mahdottoman" tilan, voit yhdistää nämä arvot "tilaksi", jonka on oltava yksi kolmesta arvosta: `'typing'`, `'submitting'`, tai `'success'`.
+* **Ovatko samat tiedot jo saatavilla toisessa tilamuuttujassa?** Toinen paradoksi: `isEmpty` ja `isTyping` eivät voi olla arvoltaan `true` samaan aikaan. Tekemällä niistä erilliset tilamuuttujat, vaarana on, että ne menevät sekaisin ja aiheuttavat virheitä. Onneksi voit poistaa `isEmpty` ja sen sijaan tarkistaa `answer.length === 0`.
+* **Voiko saman tiedon saada toisen tilamuuttujan käänteisluvusta?** `isError`:ia ei tarvita, sillä voit sen sijaan tarkistaa `error !== null`.
-* **Does this state cause a paradox?** For example, `isTyping` and `isSubmitting` can't both be `true`. A paradox usually means that the state is not constrained enough. There are four possible combinations of two booleans, but only three correspond to valid states. To remove the "impossible" state, you can combine these into a `status` that must be one of three values: `'typing'`, `'submitting'`, or `'success'`.
-* **Is the same information available in another state variable already?** Another paradox: `isEmpty` and `isTyping` can't be `true` at the same time. By making them separate state variables, you risk them going out of sync and causing bugs. Fortunately, you can remove `isEmpty` and instead check `answer.length === 0`.
-* **Can you get the same information from the inverse of another state variable?** `isError` is not needed because you can check `error !== null` instead.
-
-After this clean-up, you're left with 3 (down from 7!) *essential* state variables:
+Tämän siivouksen jälkeen jäljelle jää 3 (7:stä!) *välttämätöntä* tilamuuttujaa:
```js
const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
-const [status, setStatus] = useState('typing'); // 'typing', 'submitting', or 'success'
+const [status, setStatus] = useState('typing'); // 'typing', 'submitting', tai 'success'
```
-
-You know they are essential, because you can't remove any of them without breaking the functionality.
+Tiedät, että ne ovat välttämättömiä, kun et voi poistaa yhtään niistä rikkomatta toiminnallisuutta.
-#### Eliminating “impossible” states with a reducer {/*eliminating-impossible-states-with-a-reducer*/}
+#### Mahdottomien tilojen poistaminen reducerilla {/*eliminating-impossible-states-with-a-reducer*/}
-These three variables are a good enough representation of this form's state. However, there are still some intermediate states that don't fully make sense. For example, a non-null `error` doesn't make sense when `status` is `'success'`. To model the state more precisely, you can [extract it into a reducer.](/learn/extracting-state-logic-into-a-reducer) Reducers let you unify multiple state variables into a single object and consolidate all the related logic!
+Nämä kolme muuttujaa ovat tarpeeksi kuvaamaan tämän lomakkeen tilaa. Kuitenkin, on jotain välitiloja, jotka eivät ole järkeviä. Esimerkiksi, ei-null `error` ei ole järkevä kun `status` on `success`. Tilan tarkemmaksi mallintamiseksi, voit käyttää [reduceria.](/learn/extracting-state-logic-into-a-reducer) Reducerien avulla voit yhdistää useita tilamuuttujia yhdeksi olioksi ja tiivistää liittyvät logiikat yhteen!
-### Step 5: Connect the event handlers to set state {/*step-5-connect-the-event-handlers-to-set-state*/}
+### 5. Vaihe: Yhdistä tapahtumakäsittelijät tilan asettamiseen {/*step-5-connect-the-event-handlers-to-set-state*/}
-Lastly, create event handlers that update the state. Below is the final form, with all event handlers wired up:
+Lopuksi, luo tapahtumakäsittelijät, jotka asettavat tilamuuttujat. Alla on lopullinen lomake, jossa kaikki tapahtumakäsittelijät on kytketty:
@@ -485,17 +481,17 @@ function submitForm(answer) {
-Although this code is longer than the original imperative example, it is much less fragile. Expressing all interactions as state changes lets you later introduce new visual states without breaking existing ones. It also lets you change what should be displayed in each state without changing the logic of the interaction itself.
+Vaikka tämä koodi ei ole enää alkuperäinen imperatiivinen esimerkki, se on kestävempi. Kaikkien vuorovaikutuksien ilmaiseminen tilamuutoksina antaa sinun ottaa käyttöön uusia visuaalisia tiloja rikkomatta olemassa olevia tiloja. Se myös antaa sinun muuttaa mitä tulisi näyttää eri tiloissa muuttamatta toimintalogiikkaa itsessään.
-* Declarative programming means describing the UI for each visual state rather than micromanaging the UI (imperative).
-* When developing a component:
- 1. Identify all its visual states.
- 2. Determine the human and computer triggers for state changes.
- 3. Model the state with `useState`.
- 4. Remove non-essential state to avoid bugs and paradoxes.
- 5. Connect the event handlers to set state.
+* Deklaratiivinen ohjelmointi tarkoittaa käyttöliittymän kuvaamista jokaiselle visuaaliselle tilalle toisin kuin käyttöliittymän mikromanagerointi (imperatiivinen).
+* Komponenttia kehitettäessä:
+ 1. Tunnista kaikki sen visuaaliset tilat.
+ 2. Määritä ihmisen ja tietokoneen aiheuttamat tilamuutokset.
+ 3. Mallinna tila `useState`:lla.
+ 4. Poista epäolennainen tila välttääksesi bugeja ja paradokseja.
+ 5. Yhdistä tapahtumakäsittelijät tilan asettamiseen.
@@ -503,11 +499,11 @@ Although this code is longer than the original imperative example, it is much le
-#### Add and remove a CSS class {/*add-and-remove-a-css-class*/}
+#### Lisää ja poista CSS luokka {/*add-and-remove-a-css-class*/}
-Make it so that clicking on the picture *removes* the `background--active` CSS class from the outer ``, but *adds* the `picture--active` class to the `
`. Clicking the background again should restore the original CSS classes.
+Toteuta tämä siten, että kuvan klikkaaminen *poistaa* `background--active` CSS luokan sitä ympäröivästä `
`, mutta *lisää* `picture--active` luokan `
` elementtiin. Taustan klikkaaminen uudestaan palauttaa alkuperäiset luokat.
-Visually, you should expect that clicking on the picture removes the purple background and highlights the picture border. Clicking outside the picture highlights the background, but removes the picture border highlight.
+Visuaalisesti tulisi odottaa, että klikkaaminen poistaa violetin taustan ja korostaa kuvan reunoja. Kuvan ulkopuolelta klikkaaminen korostaa kuvan taustaa, mutta poistaa kuvan reunojen korostuksen.
@@ -556,14 +552,14 @@ body { margin: 0; padding: 0; height: 250px; }
-This component has two visual states: when the image is active, and when the image is inactive:
+Tällä komponentilla on kaksi visuaalista tilaa: kun kuva on aktiivinen ja kun kuva on inaktiivinen:
-* When the image is active, the CSS classes are `background` and `picture picture--active`.
-* When the image is inactive, the CSS classes are `background background--active` and `picture`.
+* Kun kuva on aktiivinen, CSS luokat ovat `background` ja `picture picture--active`.
+* Kun kuva on inaktiivinen, CSS luokat ovat `background background--active` ja `picture`.
-A single boolean state variable is enough to remember whether the image is active. The original task was to remove or add CSS classes. However, in React you need to *describe* what you want to see rather than *manipulate* the UI elements. So you need to calculate both CSS classes based on the current state. You also need to [stop the propagation](/learn/responding-to-events#stopping-propagation) so that clicking the image doesn't register as a click on the background.
+Yksi totuusarvo-tilamuuttuja on tarpeeksi muistamaan onko kuva aktiivinen. Alkuperäinen tehtävä oli poistaa tai lisätä CSS luokkia. Kuitenkin Reactissa sinun täytyy *kuvailla' mitä haluat nähdä käyttöliittymäelementtien *manipuloinnin* sijaan. Joten sinun tulee laskea molemmat CSS luokat nykyisen tilan pohjalta. Sinun täytyy myös [estää propagointi](/learn/responding-to-events#stopping-propagation), jotta kuvan klikkaaminen ei rekisteröidy taustakuvan klikkauksena.
-Verify that this version works by clicking the image and then outside of it:
+Tarkista, että tämä versio toimii klikkaamalla kuvaa ja sen ulkopuolelta:
@@ -630,7 +626,7 @@ body { margin: 0; padding: 0; height: 250px; }
-Alternatively, you could return two separate chunks of JSX:
+Vaihtoehtoisesti, voisit palauttaa kaksi erillistä JSX lohkoa:
@@ -697,13 +693,13 @@ body { margin: 0; padding: 0; height: 250px; }
-Keep in mind that if two different JSX chunks describe the same tree, their nesting (first `` → first `
`) has to line up. Otherwise, toggling `isActive` would recreate the whole tree below and [reset its state.](/learn/preserving-and-resetting-state) This is why, if a similar JSX tree gets returned in both cases, it is better to write them as a single piece of JSX.
+Muista, että jos kaksi eri JSX lohkoa kuvaa samaa puuta, niiden sisennysten (ensimmäinen `
` → ensimmäinen `
`) tulisi vastata toisiaan. Muutoin, `isActive`:n vaihtaminen loisi koko puun uudelleen ja [palauttaisi sen tilan.](/learn/preserving-and-resetting-state) Jos samanlaiset JSX puut palautetaan molemmissa tiloissa, on parempi kirjoittaa ne samassa palasessa JSX:ää.
-#### Profile editor {/*profile-editor*/}
+#### Profiilieditori {/*profile-editor*/}
-Here is a small form implemented with plain JavaScript and DOM. Play with it to understand its behavior:
+Tässä on pieni lomake toteutettuna perinteiselllä JavaScriptilla ja DOM:lla. Leiki tämän kanssa ymmärtääksesi sen toimintaa:
@@ -800,11 +796,11 @@ label { display: block; margin-bottom: 20px; }
-This form switches between two modes: in the editing mode, you see the inputs, and in the viewing mode, you only see the result. The button label changes between "Edit" and "Save" depending on the mode you're in. When you change the inputs, the welcome message at the bottom updates in real time.
+Tämä lomake vaihtaa kahden tilan välillä: muokkaustilassa näet kentät ja katselutilassa näet vain lopputuloksen. Painikkeen teksti vaihtuu "Edit ja "Save" välillä riippuen missä tilassa olet. Kun muutat kenttiä, tervetuloa -viesti pohjalla päivittyy reaaliajassa.
-Your task is to reimplement it in React in the sandbox below. For your convenience, the markup was already converted to JSX, but you'll need to make it show and hide the inputs like the original does.
+Tehtäväsi on toteuttaa tämä lomake Reactilla. Avuksesi merkintäkoodi on jo muutettu JSX:ksi, mutta sinun tulee toteuttaa kenttien näyttäminen ja piilottaminen juuri kuten alkuperäinen.
-Make sure that it updates the text at the bottom, too!
+Varmista, että se päivittää tekstin lopussa myös!
@@ -839,9 +835,9 @@ label { display: block; margin-bottom: 20px; }
-You will need two state variables to hold the input values: `firstName` and `lastName`. You're also going to need an `isEditing` state variable that holds whether to display the inputs or not. You should _not_ need a `fullName` variable because the full name can always be calculated from the `firstName` and the `lastName`.
+Tarvitset kaksi eri tilamuuttujaa pitämään kenttien arvoja: `firstName` ja `lastName`. Tarvitset myös `isEditing` tilamuuttujan joka pitää yllä näytetäänkö kenttiä vai ei. _Et_ tarvitse `fullName` muuttujaa, koska koko nimi voidaan laskea `firstName` ja `lastName` muuttujien avulla.
-Finally, you should use [conditional rendering](/learn/conditional-rendering) to show or hide the inputs depending on `isEditing`.
+Lopuksi, sinun tulisi käyttää [ehdollista renderöintiä](/learn/conditional-rendering) näyttääksesi tai piilottaaksesi syötekentät riippuen `isEditing` muuttujan tilasta.
@@ -899,13 +895,13 @@ label { display: block; margin-bottom: 20px; }
-Compare this solution to the original imperative code. How are they different?
+Vertaa tätä ratkaisua alkuperäiseen imperatiiviseen koodiin. Miten ne poikkeavat?
-#### Refactor the imperative solution without React {/*refactor-the-imperative-solution-without-react*/}
+#### Kehitä imperatiivinen ratkaisu ilman Reactia {/*refactor-the-imperative-solution-without-react*/}
-Here is the original sandbox from the previous challenge, written imperatively without React:
+Tässä on alkuperäinen hiekkalaatikko aikaisemmasta haasteesta, imperatiivisesti kirjoitettuna ilman Reactia:
@@ -1002,9 +998,9 @@ label { display: block; margin-bottom: 20px; }
-Imagine React didn't exist. Can you refactor this code in a way that makes the logic less fragile and more similar to the React version? What would it look like if the state was explicit, like in React?
+Kuvitte, että Reactia ei olisi olemassa. Voisitko kirjottaa tämän koodin tavalla, joka tekee logiikasta vankempaa ja lähemmäs Reactin tapaa? Miltä se näyttäisi, jos tila olisi eksplisiittistä kuten Reactissa?
-If you're struggling to think where to start, the stub below already has most of the structure in place. If you start here, fill in the missing logic in the `updateDOM` function. (Refer to the original code where needed.)
+Jos et tiedä mistä aloittaisit, alla on suurin osa rakenteesta valmiina. Jos aloitat tästä, täytä puuttuva logiikka `updateDOM` fuktiosta. (Viittaa alkuperäiseen koodiin tarvittaessa.)
@@ -1111,7 +1107,7 @@ label { display: block; margin-bottom: 20px; }
-The missing logic included toggling the display of inputs and content, and updating the labels:
+Puuttuva logiikka sisältää kenttien ja sisällön piilottamisen ja näyttämisen, lisäksi painikkeen tekstin päivittämisen:
@@ -1228,7 +1224,7 @@ label { display: block; margin-bottom: 20px; }
-The `updateDOM` function you wrote shows what React does under the hood when you set the state. (However, React also avoids touching the DOM for properties that have not changed since the last time they were set.)
+`updateDOM` funktio, jonka kirjoitit näyttää mitä React tekee pellin alla kun asetat tilan. (Kuitenkin, React myös välttää koskemasta DOM:iin, kohteissa jotka eivät ole muuttuneet viimeisestä renderöinnistä.)
diff --git a/src/content/learn/referencing-values-with-refs.md b/src/content/learn/referencing-values-with-refs.md
index da5d864ab..1dfa7ddc4 100644
--- a/src/content/learn/referencing-values-with-refs.md
+++ b/src/content/learn/referencing-values-with-refs.md
@@ -1,49 +1,49 @@
---
-title: 'Referencing Values with Refs'
+title: 'Arvoihin viittaaminen Refillä'
---
-When you want a component to "remember" some information, but you don't want that information to [trigger new renders](/learn/render-and-commit), you can use a *ref*.
+Kun haluat komponentin "muistavan" jotain tietoa, mutta et halua tiedon [triggeröivän uudelleenrenderöintiä](/learn/render-and-commit), voit käyttää *refiä*.
-- How to add a ref to your component
-- How to update a ref's value
-- How refs are different from state
-- How to use refs safely
+- Miten lisätä ref komponenttiisi
+- Miten päivittää refin arvo
+- Miten refit eroavat tilasta
+- Miten käyttää refiä turvallisesti
-## Adding a ref to your component {/*adding-a-ref-to-your-component*/}
+## Refin lisääminen komponenttiisi {/*adding-a-ref-to-your-component*/}
-You can add a ref to your component by importing the `useRef` Hook from React:
+Voit lisätä refin komponenttiisi importaamalla `useRef` Hookin Reactista:
```js
import { useRef } from 'react';
```
-Inside your component, call the `useRef` Hook and pass the initial value that you want to reference as the only argument. For example, here is a ref to the value `0`:
+Komponenttisi sisällä kutsu `useRef` hookkia ja välitä oletusarvo, jota haluat viitata ainoana argumenttina. Esimerkiksi, tässä on ref arvolla `0`:
```js
const ref = useRef(0);
```
-`useRef` returns an object like this:
+`useRef` palauttaa seuraavanlaisen olion:
```js
{
- current: 0 // The value you passed to useRef
+ current: 0 // Arvo, jonka välitit useRef funktiolle
}
```
-
+
-You can access the current value of that ref through the `ref.current` property. This value is intentionally mutable, meaning you can both read and write to it. It's like a secret pocket of your component that React doesn't track. (This is what makes it an "escape hatch" from React's one-way data flow--more on that below!)
+Pääset käsiksi nykyiseen refin arvoon `ref.current` ominaisuuden kautta. Tämä arvo on tarkoituksella muokattavissa, eli voit sekä lukea että kirjoittaa siihen. Se on kuin salainen tasku komponentissasi, jota React ei seuraa. (Tämä on se mikä tekee refistä "pelastusluukun" Reactin yksisuuntaisesta datavirtauksesta--josta alla lisää!)
-Here, a button will increment `ref.current` on every click:
+Täss, painike kasvattaa `ref.current` arvoa joka kerta kun sitä painetaan:
@@ -68,20 +68,20 @@ export default function Counter() {
-The ref points to a number, but, like [state](/learn/state-a-components-memory), you could point to anything: a string, an object, or even a function. Unlike state, ref is a plain JavaScript object with the `current` property that you can read and modify.
+Ref osoittaa numeroon, mutta, kuten [tila](/learn/state-a-components-memory), voit viitata mihin tahansa: merkkijonoon, olioon tai jopa funktioon. Tilaan verrattuna, ref on tavallinen JavaScript-olio, jolla on `current`-ominaisuus, jota voit lukea ja muokata.
-Note that **the component doesn't re-render with every increment.** Like state, refs are retained by React between re-renders. However, setting state re-renders a component. Changing a ref does not!
+Huomaa, että **komponentti ei renderöidy uudelleen joka kerta kun arvo kasvaa.** Kuten tila, refit säilyvät Reactin uudelleenrenderöintien välillä. Kuitenkin, tilan asettaminen uudelleenrenderöi komponentin. Refin päivittäminen ei!
-## Example: building a stopwatch {/*example-building-a-stopwatch*/}
+## Esimerkki: sekuntikellon rakentaminen {/*example-building-a-stopwatch*/}
-You can combine refs and state in a single component. For example, let's make a stopwatch that the user can start or stop by pressing a button. In order to display how much time has passed since the user pressed "Start", you will need to keep track of when the Start button was pressed and what the current time is. **This information is used for rendering, so you'll keep it in state:**
+Voit yhdistää refin ja tilan samaan komponenttiin. Esimerkiksi, tehdään sekuntikello, jonka käyttäjä voi käynnistää tai pysäyttää nappia painamalla. Jotta voidaan näyttää kuinka paljon aikaa on kulunut siitä kun käyttäjä on painanut "Start" nappia, sinun täytyy pitää kirjaa siitä milloin käyttäjä painoi "Start" nappia ja mitä nykyinen aika on. **Tätä tietoa käytetään renderöinnissä, joten pidä se tilassa:**
```js
const [startTime, setStartTime] = useState(null);
const [now, setNow] = useState(null);
```
-When the user presses "Start", you'll use [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval) in order to update the time every 10 milliseconds:
+Kun käyttäjä painaa "Start", käytät [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval) funktiota päivittääksesi ajan joka 10 millisekuntin välien:
@@ -93,12 +93,12 @@ export default function Stopwatch() {
const [now, setNow] = useState(null);
function handleStart() {
- // Start counting.
+ // Aloita laskeminen.
setStartTime(Date.now());
setNow(Date.now());
setInterval(() => {
- // Update the current time every 10ms.
+ // Päivitä tämänhetkinen aika joka 10ms välein.
setNow(Date.now());
}, 10);
}
@@ -121,7 +121,7 @@ export default function Stopwatch() {
-When the "Stop" button is pressed, you need to cancel the existing interval so that it stops updating the `now` state variable. You can do this by calling [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), but you need to give it the interval ID that was previously returned by the `setInterval` call when the user pressed Start. You need to keep the interval ID somewhere. **Since the interval ID is not used for rendering, you can keep it in a ref:**
+Kun "Stop" nappia painetaan, sinun täytyy peruuttaa olemassa oleva ajastin, jotta se lopettaa `now` tilamuuttujan päivittämisen. Voit tehdä tämän kutsumalla [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) funktiota, mutta sinun täytyy antaa sille ajastimen ID, joka palautettiin aiemmin `setInterval` kutsun kautta kun käyttäjä painoi "Start". Sinun täytyy pitää ajastimen ID jossain. **Koska ajastimen ID:tä ei käytetä renderöinnissä, voit pitää sen refissä:**
@@ -168,20 +168,20 @@ export default function Stopwatch() {
-When a piece of information is used for rendering, keep it in state. When a piece of information is only needed by event handlers and changing it doesn't require a re-render, using a ref may be more efficient.
+Kun tietoa käytetään renderöinnissä, pidä se tilassa. Kun tietoa tarvitaan vain tapahtumankäsittelijöissä ja sen muuttaminen ei vaadi uudelleenrenderöintiä, refin käyttäminen voi olla tehokkaampaa.
-## Differences between refs and state {/*differences-between-refs-and-state*/}
+## Refin ja tilan erot {/*differences-between-refs-and-state*/}
-Perhaps you're thinking refs seem less "strict" than state—you can mutate them instead of always having to use a state setting function, for instance. But in most cases, you'll want to use state. Refs are an "escape hatch" you won't need often. Here's how state and refs compare:
+Ehkäpä ajattelet, että refit vaikuttavat vähemmän "tiukilta" kuin tila—voit muokata niitä tilan asettamisfunktion käyttämisen sijaan. Mutta useimmissa tapauksissa haluat käyttää tilaa. Refit ovat "pelastusluukku", jota et tarvitse usein. Tässä on miten tila ja refit vastaavat toisiaan:
-| refs | state |
-| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
-| `useRef(initialValue)` returns `{ current: initialValue }` | `useState(initialValue)` returns the current value of a state variable and a state setter function ( `[value, setValue]`) |
-| Doesn't trigger re-render when you change it. | Triggers re-render when you change it. |
-| Mutable—you can modify and update `current`'s value outside of the rendering process. | "Immutable"—you must use the state setting function to modify state variables to queue a re-render. |
-| You shouldn't read (or write) the `current` value during rendering. | You can read state at any time. However, each render has its own [snapshot](/learn/state-as-a-snapshot) of state which does not change.
+| ref | tila |
+| --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
+| `useRef(initialValue)` palauttaa `{ current: initialValue }` | `useState(initialValue)` palauttaa tilamuuttujan nykyisen arvon ja tilan asetusfunktion ( `[value, setValue]`) |
+| Ei triggeröi uudelleenrenderöintiä kun muutat sitä. | Triggeröi uudelleenrenderöinnin kun muutat sitä. |
+| Mutatoitavissa—voit muokata ja päivittää `current`:n arvoa renderöintiprosessin ulkopuolella. | Ei-mutatoitavissa—sinun täytyy käyttää tilan asetusfunktiota muokataksesi tilamuuttujaa jonottaaksesi uudelleenrenderöinti. |
+| Sinuun ei tulisi lukea (tai kirjoittaa) `current` arvoa kesken renderöinnin. | Voit lukea tilaa koska tahansa. Kuitenkin, jokaisella renderöinnillä on oma [tilakuvansa](/learn/state-as-a-snapshot) tilasta, joka ei muutu. |
-Here is a counter button that's implemented with state:
+Tässä on laskuri-painike, joka on toteutettu tilalla:
@@ -205,9 +205,9 @@ export default function Counter() {
-Because the `count` value is displayed, it makes sense to use a state value for it. When the counter's value is set with `setCount()`, React re-renders the component and the screen updates to reflect the new count.
+Koska `count` arvo näytetään, on järkevää käyttää tilaa arvon tallentamiseen. Kun laskurin arvo asetetaan `setCount()` funktiolla, React renderöi komponentin uudelleen ja ruutu päivittyy vastaamaan uutta arvoa.
-If you tried to implement this with a ref, React would never re-render the component, so you'd never see the count change! See how clicking this button **does not update its text**:
+Jos yrität toteuttaa tämän refillä, React ei koskaan renderöi komponenttia uudelleen, joten et koskaan näe laskurin arvon muuttuvan! Katso miten tämän painikkeen klikkaaminen **ei päivitä sen tekstiä**:
@@ -218,7 +218,7 @@ export default function Counter() {
let countRef = useRef(0);
function handleClick() {
- // This doesn't re-render the component!
+ // Tämä ei uudeleenrenderöi komponenttia!
countRef.current = countRef.current + 1;
}
@@ -232,68 +232,68 @@ export default function Counter() {
-This is why reading `ref.current` during render leads to unreliable code. If you need that, use state instead.
+Tämä on syy miksi refin `current` arvon lukeminen renderöinnin aikana johtaa epäluotettavaan koodiin. Jos tarvitset tätä, käytä tilaa sen sijaan.
-#### How does useRef work inside? {/*how-does-use-ref-work-inside*/}
+#### Miten useRef toimii? {/*how-does-use-ref-work-inside*/}
-Although both `useState` and `useRef` are provided by React, in principle `useRef` could be implemented _on top of_ `useState`. You can imagine that inside of React, `useRef` is implemented like this:
+Vaikka sekä `useState` että `useRef` on tarjottu Reactin puolesta, periaatteessa `useRef` voitaisiin toteuttaa `useState`:n päälle. Voit kuvitella, että Reactin sisällä `useRef` on toteutettu näin:
```js
-// Inside of React
+// Reactin sisällä
function useRef(initialValue) {
const [ref, unused] = useState({ current: initialValue });
return ref;
}
```
-During the first render, `useRef` returns `{ current: initialValue }`. This object is stored by React, so during the next render the same object will be returned. Note how the state setter is unused in this example. It is unnecessary because `useRef` always needs to return the same object!
+Ensimmäisen renderöinnin aikana, `useRef` palauttaa `{ current: initialValue }`. Tämä olio tallennetaan Reactin puolelle, joten seuraavalla renderöinnillä sama olio palautetaan. Huomaa, että tilan asetusfunktiota ei käytetä tässä esimerkissä. Se on tarpeeton, koska `useRef`:n tarvitsee aina palauttaa sama olio!
-React provides a built-in version of `useRef` because it is common enough in practice. But you can think of it as a regular state variable without a setter. If you're familiar with object-oriented programming, refs might remind you of instance fields--but instead of `this.something` you write `somethingRef.current`.
+React tarjoaa sisäänrakennetun version `useRef`:sta koska se on tarpeeksi yleinen. Mutta voit ajatella sitä tavallisena tilamuuttujana ilman asetusfunktiota. Jos olet tutustunut olio-ohjelmointiin, refit voivat muistuttaa sinua instanssimuuttujista, mutta `this.something` sijaan kirjoitat `somethingRef.current`.
-## When to use refs {/*when-to-use-refs*/}
+## Milloin käyttää refiä {/*when-to-use-refs*/}
-Typically, you will use a ref when your component needs to "step outside" React and communicate with external APIs—often a browser API that won't impact the appearance of the component. Here are a few of these rare situations:
+Tyypillisesti, käytät refiä kun komponenttisi täytyy "astua Reactin ulkopuolelle" ja kommunikoida ulkoisten rajapintojen kanssa—usein selaimen API:n, joka ei vaikuta komponentin ulkonäköön. Tässä on muutamia näitä harvinaisia tilanteita:
-- Storing [timeout IDs](https://developer.mozilla.org/docs/Web/API/setTimeout)
-- Storing and manipulating [DOM elements](https://developer.mozilla.org/docs/Web/API/Element), which we cover on [the next page](/learn/manipulating-the-dom-with-refs)
-- Storing other objects that aren't necessary to calculate the JSX.
+- Tallentaakseen [ajastimen ID:t](https://developer.mozilla.org/docs/Web/API/setTimeout)
+- Tallentaakseen ja muokatakseen [DOM elementtejä](https://developer.mozilla.org/docs/Web/API/Element), joita käsittelemme [seuraavalla sivulla](/learn/manipulating-the-dom-with-refs)
+- Tallentaakseen muita oliota, jotka eivät ole tarpeellisia JSX:n laskemiseen.
-If your component needs to store some value, but it doesn't impact the rendering logic, choose refs.
+Jos komponenttisi tarvitsee tallentaa arvoa, mutta se ei vaikuta renderöinnin logiikkaan, valitse ref.
-## Best practices for refs {/*best-practices-for-refs*/}
+## Parhaat käytännöt refille {/*best-practices-for-refs*/}
-Following these principles will make your components more predictable:
+Näitä periaatteita noudattaen komponenteistasi tulee ennakoitavampia:
-- **Treat refs as an escape hatch.** Refs are useful when you work with external systems or browser APIs. If much of your application logic and data flow relies on refs, you might want to rethink your approach.
-- **Don't read or write `ref.current` during rendering.** If some information is needed during rendering, use [state](/learn/state-a-components-memory) instead. Since React doesn't know when `ref.current` changes, even reading it while rendering makes your component's behavior difficult to predict. (The only exception to this is code like `if (!ref.current) ref.current = new Thing()` which only sets the ref once during the first render.)
+- **Käsittele refejä kuten pelastusluukkua.** Refit ovat hyödyllisiä kun työskentelet ulkoisten järjestelmien tai selaimen API:n kanssa. Jos suuri osa sovelluksesi logiikasta ja datavirtauksesta riippuu refeistä, saatat haluta miettiä lähestymistapaasi uudelleen.
+- **Älä lue tai kirjoita `ref.current`:iin kesken renderöinnin.** Jos jotain tietoa tarvitaan kesken renderöinnin, käytä [tilaa](/learn/state-a-components-memory) sen sijaan. Koska React ei tiedä milloin `ref.current` muuttuu, jopa sen lukeminen renderöinnin aikana tekee komponenttisi käyttäytymisestä vaikeasti ennakoitavaa. (Ainoa poikkeus tähän on koodi kuten `if(!ref.current) ref.current = new Thing()` joka asettaa refin vain kerran ensimäisellä renderöinnillä.)
-Limitations of React state don't apply to refs. For example, state acts like a [snapshot for every render](/learn/state-as-a-snapshot) and [doesn't update synchronously.](/learn/queueing-a-series-of-state-updates) But when you mutate the current value of a ref, it changes immediately:
+Reactin tilan rajoitukset eivät päde refiin. Esimerkiksi tila toimii [tilannekuvana jokaiselle renderöinnille](/learn/state-as-a-snapshot) ja [se ei päivity synkronisesti.](/learn/queueing-a-series-of-state-updates) Mutta kun muokkaat refin nykyistä arvoa, se muuttuu välittömästi:
```js
ref.current = 5;
console.log(ref.current); // 5
```
-This is because **the ref itself is a regular JavaScript object,** and so it behaves like one.
+Tämä johtuu siitä, että **ref on tavallinen JavaScript olio**, joten se käyttäytyy samoin.
-You also don't need to worry about [avoiding mutation](/learn/updating-objects-in-state) when you work with a ref. As long as the object you're mutating isn't used for rendering, React doesn't care what you do with the ref or its contents.
+Sinun ei myöskään tarvitse huolehtia [mutaatioiden välttämistä](/learn/updating-objects-in-state), kun työskentelet refin kanssa. Jos olio, jota muutat ei ole käytössä renderöinnissä, React ei välitä mitä teet refin tai sen sisällön kanssa.
-## Refs and the DOM {/*refs-and-the-dom*/}
+## Ref ja DOM {/*refs-and-the-dom*/}
-You can point a ref to any value. However, the most common use case for a ref is to access a DOM element. For example, this is handy if you want to focus an input programmatically. When you pass a ref to a `ref` attribute in JSX, like ``, React will put the corresponding DOM element into `myRef.current`. You can read more about this in [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs)
+Voit osoittaa refin mihin tahansa arvoon. Kuitenkin yleisin käyttökohde refille on DOM elementin käsittely. Esimerkiksi, tämä on kätevää jos haluat focusoida syöttölaatikon ohjelmakoodissa. Kun annat refin `ref`-attribuuttiin JSX:ssä, kuten `
`, React asettaa vastaavan DOM elementin `myRef.current`:iin. Voit lukea lisää tästä [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs)
-- Refs are an escape hatch to hold onto values that aren't used for rendering. You won't need them often.
-- A ref is a plain JavaScript object with a single property called `current`, which you can read or set.
-- You can ask React to give you a ref by calling the `useRef` Hook.
-- Like state, refs let you retain information between re-renders of a component.
-- Unlike state, setting the ref's `current` value does not trigger a re-render.
-- Don't read or write `ref.current` during rendering. This makes your component hard to predict.
+- Refit ovat pelastusluukku arvojen pitämiseen, jotka eivät ole käytössä renderöinnissä. Et tarvitse niitä usein.
+- Ref on perus JavaScript-olio, jolla on yksi ominaisuus nimeltään `current`, jonka voit lukea tai asettaa.
+- Voit pyytää Reactia antamaan sinulle refin kutsumalla `useRef` Hookia.
+- Kuten tila, refit antavat sinun säilyttää tietoa komponentin uudelleenrenderöinnin välillä.
+- Toisin kuin tila, refin `current`-arvon asettaminen ei aiheuta uudelleenrenderöintiä.
+- Älä lue tai kirjota `ref.current`-arvoa renderöinnin aikana. Tämä tekee komponentistasi vaikeasti ennustettavan.
@@ -301,13 +301,13 @@ You can point a ref to any value. However, the most common use case for a ref is
-#### Fix a broken chat input {/*fix-a-broken-chat-input*/}
+#### Korjaa rikkinäinen chat-kenttä {/*fix-a-broken-chat-input*/}
-Type a message and click "Send". You will notice there is a three second delay before you see the "Sent!" alert. During this delay, you can see an "Undo" button. Click it. This "Undo" button is supposed to stop the "Sent!" message from appearing. It does this by calling [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) for the timeout ID saved during `handleSend`. However, even after "Undo" is clicked, the "Sent!" message still appears. Find why it doesn't work, and fix it.
+Kirjoita viesti ja paina "Send" painiketta. Huomaat, että viesti ilmestyy kolmen sekunnin viiveellä. Tämän ajan aikana näet "Undo" painikkeen. Paina sitä. Tämä "Undo" painike on tarkoitettu pysäyttämään "Sent!" viesti näkyvistä. Se tekee tämän kutsumalla [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) funktiota timeout ID:llä, joka tallennettiin `handleSend` funktion aikana. Kuitenkin, vaikka "Undo" painiketta painettaisiin, "Sent!" viesti ilmestyy silti. Etsi miksi se ei toimi, ja korjaa se.
-Regular variables like `let timeoutID` don't "survive" between re-renders because every render runs your component (and initializes its variables) from scratch. Should you keep the timeout ID somewhere else?
+Tavalliset muuttujat kuten `let timeoutID` eivät "selviä" uudelleenrenderöinnin välillä, koska jokainen renderöinti ajaa komponenttisi (ja alustaa sen muuttujat) alusta. Pitäisikö sinun pitää timeout ID jossain muualla?
@@ -360,7 +360,7 @@ export default function Chat() {
-Whenever your component re-renders (such as when you set state), all local variables get initialized from scratch. This is why you can't save the timeout ID in a local variable like `timeoutID` and then expect another event handler to "see" it in the future. Instead, store it in a ref, which React will preserve between renders.
+Kun komponenttisi uudelleenrenderöidään (kuten tilan asettamisen yhteydessä), kaikki paikalliset muuttujat alustetaan alusta. Tämä on syy siihen, miksi et voi tallentaa timeout ID:tä paikalliseen muuttujaan kuten `timeoutID` ja sitten odottaa toisen tapahtumankäsittelijän "näkevän" sen tulevaisuudessa. Tallenna se refiin, jota React säilyttää renderöintien välillä.
@@ -412,9 +412,9 @@ export default function Chat() {
-#### Fix a component failing to re-render {/*fix-a-component-failing-to-re-render*/}
+#### Korjaa komponentin uudelleenrenderöinti {/*fix-a-component-failing-to-re-render*/}
-This button is supposed to toggle between showing "On" and "Off". However, it always shows "Off". What is wrong with this code? Fix it.
+Tämän painikkeen on tarkoitus vaihtaa "On" ja "Off" välillä. Kuitenkin, se näyttää aina "Off". Mikä tässä koodissa on vikana? Korjaa se.
@@ -438,7 +438,7 @@ export default function Toggle() {
-In this example, the current value of a ref is used to calculate the rendering output: `{isOnRef.current ? 'On' : 'Off'}`. This is a sign that this information should not be in a ref, and should have instead been put in state. To fix it, remove the ref and use state instead:
+Tässä esimerkissä, refin nykyinen arvo käytetään renderöinnin tuloksen laskemiseen: `{isOnRef.current ? 'On' : 'Off'}`. Tämä on merkki siitä, että tämä tieto ei pitäisi olla refissä, ja sen pitäisi olla tilassa. Korjataksesi sen, poista ref ja käytä tilaa sen sijaan:
@@ -462,17 +462,17 @@ export default function Toggle() {
-#### Fix debouncing {/*fix-debouncing*/}
+#### Korjaa debounce {/*fix-debouncing*/}
-In this example, all button click handlers are ["debounced".](https://redd.one/blog/debounce-vs-throttle) To see what this means, press one of the buttons. Notice how the message appears a second later. If you press the button while waiting for the message, the timer will reset. So if you keep clicking the same button fast many times, the message won't appear until a second *after* you stop clicking. Debouncing lets you delay some action until the user "stops doing things".
+Tässä esimerkissä kaikki painikkeiden klikkaukset ovat ["debounced".](https://redd.one/blog/debounce-vs-throttle) Nähdäksesi mitä tämä tarkoittaa, paina yhtä painikkeista. Huomaa, kuinka viesti ilmestyy sekunnin kuluttua. Jos painat painiketta odottaessasi viestiä, ajanlaskuri nollautuu. Joten jos painat samaa painiketta nopeasti useita kertoja, viestiä ei näy ennen kuin sekunti *jälkeen* kun lopetat painamisen. Debouncing antaa sinun viivästyttää jotain toimintoa, kunnes käyttäjä "lopettaa tekemästä asioita".
-This example works, but not quite as intended. The buttons are not independent. To see the problem, click one of the buttons, and then immediately click another button. You'd expect that after a delay, you would see both button's messages. But only the last button's message shows up. The first button's message gets lost.
+Tämä esimerkki toimii, mutta ei ihan niin kuin tarkoitettiin. Painikkeet eivät ole riippumattomia. Nähdäksesi ongelman, paina yhtä painikkeista, ja paina sitten välittömästi toista painiketta. Odota hetki, ja näet molempien painikkeiden viestit. Mutta vain viimeisen painikkeen viesti näkyy. Ensimmäisen painikkeen viesti katoaa.
-Why are the buttons interfering with each other? Find and fix the issue.
+Miksi painikkeiden klikkaukset vaikuttavat toisiinsa? Etsi ja korjaa ongelma.
-The last timeout ID variable is shared between all `DebouncedButton` components. This is why clicking one button resets another button's timeout. Can you store a separate timeout ID for each button?
+Viimeisin timeout ID-muuttuja on jaettu kaikkien `DebouncedButton` -komponenttien välillä. Tämä on syy siihen, miksi yhden painikkeen klikkaaminen nollaa toisen painikkeen ajanlaskurin. Voitko tallentaa erillisen timeout ID:n jokaiselle painikkeelle?
@@ -525,7 +525,7 @@ button { display: block; margin: 10px; }
-A variable like `timeoutID` is shared between all components. This is why clicking on the second button resets the first button's pending timeout. To fix this, you can keep timeout in a ref. Each button will get its own ref, so they won't conflict with each other. Notice how clicking two buttons fast will show both messages.
+Muuttuja kuten `timeoutID` on jaettu kaikkien komponenttien välillä. Tämä on syy siihen, miksi yhden painikkeen klikkaaminen nollaa toisen painikkeen ajanlaskurin. Korjataksesi tämän, voit pitää timeoutin refissä. Jokainen painike saa oman refinsä, joten ne eivät riko toisiaan. Huomaa, kuinka nopeasti painamalla kaksi painiketta näet molempien viestit.
@@ -577,11 +577,11 @@ button { display: block; margin: 10px; }
-#### Read the latest state {/*read-the-latest-state*/}
+#### Lue viimeisin tila {/*read-the-latest-state*/}
-In this example, after you press "Send", there is a small delay before the message is shown. Type "hello", press Send, and then quickly edit the input again. Despite your edits, the alert would still show "hello" (which was the value of state [at the time](/learn/state-as-a-snapshot#state-over-time) the button was clicked).
+Tässä esimerkissä, kun painat "Lähetä", on pieni viive ennen kuin viesti näkyy. Kirjoita "hei", paina Lähetä ja muokkaa sitten nopeasti syötettä. Vaikka muokkaatkin, ilmoitus näyttää edelleen "hei" (joka oli tilan arvo [kun painiketta painettiin](/learn/state-as-a-snapshot#state-over-time)).
-Usually, this behavior is what you want in an app. However, there may be occasional cases where you want some asynchronous code to read the *latest* version of some state. Can you think of a way to make the alert show the *current* input text rather than what it was at the time of the click?
+Useiten tämä käyttäytyminen on haluttua sovelluksessa. Kuitenkin on tilanteita, joissa haluat, että jokin asynkroninen koodi lukee *viimeisimmän* tilan. Voitko keksiä tavan, jolla ilmoitus näyttää *nykyisen* syöttölaatikon tekstin, eikä sitä, mitä se oli painiketta painettaessa?
@@ -616,7 +616,7 @@ export default function Chat() {
-State works [like a snapshot](/learn/state-as-a-snapshot), so you can't read the latest state from an asynchronous operation like a timeout. However, you can keep the latest input text in a ref. A ref is mutable, so you can read the `current` property at any time. Since the current text is also used for rendering, in this example, you will need *both* a state variable (for rendering), *and* a ref (to read it in the timeout). You will need to update the current ref value manually.
+Tila toimii [kuten tilannekuva](/learn/state-as-a-snapshot), joten et voi lukea viimeisintä tilaa aikakatkaisusta kuten timeoutista. Voit kuitenkin pitää viimeisimmän syötetyn tekstin refissä. Ref on muuttuva, joten voit lukea `current` -ominaisuuden milloin tahansa. Koska nykyinen teksti käytetään myös renderöinnissä, tässä esimerkissä tarvitset *molemmat* tilamuuttujan (renderöintiä varten) *ja* refin (timeoutin lukemista varten). Sinun täytyy päivittää nykyinen ref-arvo manuaalisesti.
diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md
index 84bf904cd..65162c419 100644
--- a/src/content/learn/render-and-commit.md
+++ b/src/content/learn/render-and-commit.md
@@ -1,44 +1,58 @@
---
-title: Render and Commit
+title: Renderöi ja kommitoi
---
-Before your components are displayed on screen, they must be rendered by React. Understanding the steps in this process will help you think about how your code executes and explain its behavior.
+Ennen kuin komponenttisi näkyvät ruudulla, Reactin näytyy renderöidä ne. Tämän
+prosessin vaiheiden ymmärtäminen auttaa sinua miettimään miten koodisi suoritetaan ja
+selittämään sen käyttäytymistä.
-* What rendering means in React
-* When and why React renders a component
-* The steps involved in displaying a component on screen
-* Why rendering does not always produce a DOM update
+- Mitä renderöinti tarkoittaa Reactissa
+- Milloin ja miksi React renderöi komponentin
+- Vaaditut vaiheet komponentin näyttämiseksi näytöllä
+- Miksi renderöinti ei aina tuota DOM päivitystä
-Imagine that your components are cooks in the kitchen, assembling tasty dishes from ingredients. In this scenario, React is the waiter who puts in requests from customers and brings them their orders. This process of requesting and serving UI has three steps:
+Kuvittele, että komponenttisi ovat kokkeja keittiössä kasaamassa maukkaita ruokia raaka-aineista. Tässä skenaariossa React on tarjoilija, joka tuo ja vie asiakkaiden tilaukset. Tässä käyttöliittymän pyyntö- ja käyttöprosessissa on kolme vaihetta:
-1. **Triggering** a render (delivering the guest's order to the kitchen)
-2. **Rendering** the component (preparing the order in the kitchen)
-3. **Committing** to the DOM (placing the order on the table)
+1. **Käynnistää** renderöinti (tuoda vierailijan tilaus keittiölle)
+2. **Renderöidä** komponentti (tilauksen valmistelu keittiössä)
+3. **Kommitoida** DOM:iin (tilauksen asettaminen pöydälle)
-
-
-
+
+
+
-## Step 1: Trigger a render {/*step-1-trigger-a-render*/}
+## 1. Vaihe: Käynnistä renderöinti {/*step-1-trigger-a-render*/}
-There are two reasons for a component to render:
+On kaksi syytä miksi komponentti renderöidään:
-1. It's the component's **initial render.**
-2. The component's (or one of its ancestors') **state has been updated.**
+1. Se on komponentin **ensimmäinen renderöinti.**
+2. Komponentin (tai yhden sen vanhemman) **tila on päivittynyt.**
-### Initial render {/*initial-render*/}
+### Ensimmäinen renderöinti {/*initial-render*/}
-When your app starts, you need to trigger the initial render. Frameworks and sandboxes sometimes hide this code, but it's done by calling [`createRoot`](/reference/react-dom/client/createRoot) with the target DOM node, and then calling its `render` method with your component:
+Kun sovelluksesi käynnistyy, sinun täytyy käynnistää ensimmäinen renderöinti. Ohjelmistokehykset ja hiekkalaatikot joskus piilottavat tämän koodin, mutta se tehdään kutsumalla [`createRoot`](/reference/react-dom/client/createRoot) funktiota kohde DOM elementillä ja sitten kutsumalla sen `render` metodia komponenttisi kanssa:
@@ -63,28 +77,40 @@ export default function Image() {
-Try commenting out the `root.render()` call and see the component disappear!
+Kokeile kommentoida `root.render()` kutsu ja näet komponentin katoavan!
-### Re-renders when state updates {/*re-renders-when-state-updates*/}
+### Uudelleenrenderöityy tilan päivittyessä {/*re-renders-when-state-updates*/}
-Once the component has been initially rendered, you can trigger further renders by updating its state with the [`set` function.](/reference/react/useState#setstate) Updating your component's state automatically queues a render. (You can imagine these as a restaurant guest ordering tea, dessert, and all sorts of things after putting in their first order, depending on the state of their thirst or hunger.)
+Kun komponentti on renderöity aluksi, voit käynnistää uusia renderöintejä päivittämällä sen tilaa [`set` funktiolla.](/reference/react/useState#setstate) Komponentin tilan päivittäminen automaattisesti lisää renderöinnin jonoon. (Voit kuvitella tätä ravintolan vieraana tilaamassa teetä, jälkiruokaa, ja kaikkea muuta alkuperäisen tilauksen jälkeen, janon tai nälän tilasta riippuen.)
-
-
-
+
+
+
-## Step 2: React renders your components {/*step-2-react-renders-your-components*/}
+## 2. Vaihe: React renderöi komponenttisi {/*step-2-react-renders-your-components*/}
-After you trigger a render, React calls your components to figure out what to display on screen. **"Rendering" is React calling your components.**
+Sen jälkeen kun olet käynnistänyt renderin, React kutsuu komponenttejasi päätelläkseen mitä näyttää ruudulla. **"Renderöinti" on React kutsumassa komponenttejasi.**
-* **On initial render,** React will call the root component.
-* **For subsequent renders,** React will call the function component whose state update triggered the render.
+- **Ensimmäisen renderöinnin** yhteydessä React kutsuu juurikomponenttiasi.
+- **Seuraavissa renderöinneissä** React kutsuu komponenttia, jonka tila käynnistää renderöinnin.
-This process is recursive: if the updated component returns some other component, React will render _that_ component next, and if that component also returns something, it will render _that_ component next, and so on. The process will continue until there are no more nested components and React knows exactly what should be displayed on screen.
+Tämä prosessi on rekursiivinen: jos päivitetty komponentti palauttaa jonkin toisen komponentin, React kutsuu _sen_ komponentin seuraavaksi, ja jos se komponentti myös palauttaa jotain, se renderöi _sen_ komponentin seuraavaksi, ja niin edelleen. Tämä prosessi jatkuu kunnes ei ole enempää sisennettyjä komponentteja ja React tietää tarkalleen mitä ruudulla tulisi näkyä.
-In the following example, React will call `Gallery()` and `Image()` several times:
+Seuraavassa esimerkissä, React kutsuu `Gallery()` ja `Image()` komponentteja useita kertoja:
@@ -104,7 +130,7 @@ function Image() {
return (
);
}
@@ -119,46 +145,48 @@ root.render( );
```
```css
-img { margin: 0 10px 10px 0; }
+img {
+ margin: 0 10px 10px 0;
+}
```
-* **During the initial render,** React will [create the DOM nodes](https://developer.mozilla.org/docs/Web/API/Document/createElement) for ``, ``, and three ` ` tags.
-* **During a re-render,** React will calculate which of their properties, if any, have changed since the previous render. It won't do anything with that information until the next step, the commit phase.
+- **Ensimmäisen renderöinnin aikana** React [luo DOM nodet](https://developer.mozilla.org/docs/Web/API/Document/createElement) ``, ``, ja kolmelle ` ` tagille.
+- **Uudelleenrenderöinnin aikana,** React laskee mitkä niiden propertyistä, jos mitkään, ovat muuttuneet sitten aiemman renderöinnin. Se ei tee näillä tiedoilla mitään ennen seuraavaa commit-vaihetta.
-Rendering must always be a [pure calculation](/learn/keeping-components-pure):
+Renderöinnin on oltava aina [puhdas laskelma](/learn/keeping-components-pure):
-* **Same inputs, same output.** Given the same inputs, a component should always return the same JSX. (When someone orders a salad with tomatoes, they should not receive a salad with onions!)
-* **It minds its own business.** It should not change any objects or variables that existed before rendering. (One order should not change anyone else's order.)
+- **Samat sisääntulot, samat ulostulot.** Annettaen samat lähtötiedot, puhtaan funktion tulisi aina palauttaa sama lopputulos. (Kun joku tilaa salaatin tomaateilla, sen ei tulisi saada salaatti sipulilla!)
+- **Huolehtii omista asioistaan.** Se ei muuta yhtään oliota tai muuttujaa joka oli olemassa ennen kuin se renderöitiin. (Toisen tilaus ei pitäisi muuttaa kenenkään muun tilausta.)
-Otherwise, you can encounter confusing bugs and unpredictable behavior as your codebase grows in complexity. When developing in "Strict Mode", React calls each component's function twice, which can help surface mistakes caused by impure functions.
+Muutoin saatat kohdata hämmentäviä bugeja ja arvaamatonta käyttäytymistä kun koodipohjasi monimutkaisuuden kasvaessa. Kehittäessä "Strict Modessa," React kutsuu jokaisen komponentin funktiota kahdesti, joka nostaa pintaan epäpuhtaiden funktioiden virheitä.
-#### Optimizing performance {/*optimizing-performance*/}
+#### Tehokkuuden optimointi {/*optimizing-performance*/}
-The default behavior of rendering all components nested within the updated component is not optimal for performance if the updated component is very high in the tree. If you run into a performance issue, there are several opt-in ways to solve it described in the [Performance](https://reactjs.org/docs/optimizing-performance.html) section. **Don't optimize prematurely!**
+Päivitetyn komponentin sisäkkäisten komponenttien renderöinti oletuksena ei ole optimaalinen suorituskyvyn kannalta, jos päivittynyt komoponentti on todella korkealla puussa. Jos törmäät ongelmiin suorituskyvyssä, on useita tapoja ratkaista niitä jälkeenpäin. Näitä käydään läpi [Suorituskyky](https://reactjs.org/docs/optimizing-performance.html) osiossa. **Älä optimoi ennenaikaisesti!**
-## Step 3: React commits changes to the DOM {/*step-3-react-commits-changes-to-the-dom*/}
+## 3. Vaihe: React committaa muutokset DOM:iin {/*step-3-react-commits-changes-to-the-dom*/}
-After rendering (calling) your components, React will modify the DOM.
+Komponenttisi renderöinnin (kutsumisen) jälkeen React muuttaa DOM:ia.
-* **For the initial render,** React will use the [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild) DOM API to put all the DOM nodes it has created on screen.
-* **For re-renders,** React will apply the minimal necessary operations (calculated while rendering!) to make the DOM match the latest rendering output.
+- **Ensimmäisen renderöinnin jälkeen** React käyttää [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild) DOM API:a asettaakseen luomansa DOM nodet ruudulle.
+- **Uudelleenrenderöinteihin** React käyttää minimaalisen verran vaadittuja operaatioita (jotka lasketaan renderöinnin aikana!), jotta DOM vastaa viimeisintä renderöintitulosta.
-**React only changes the DOM nodes if there's a difference between renders.** For example, here is a component that re-renders with different props passed from its parent every second. Notice how you can add some text into the ` `, updating its `value`, but the text doesn't disappear when the component re-renders:
+**React muuttaa DOM nodeja vain jos renderöintien välissä on eroja.** Esimerkiksi, tässä on komponentti, joka uudelleenrenderöityy eri propseilla joka sekunti. Huomaa miten voit lisätä tekstiä ` ` kenttään, päivittäen sen `value`:ta, mutta teksti ei poistu kun komponentti uudelleenrenderöityy:
```js Clock.js active
-export default function Clock({ time }) {
+export default function Clock({time}) {
return (
<>
{time}
@@ -169,7 +197,7 @@ export default function Clock({ time }) {
```
```js App.js hidden
-import { useState, useEffect } from 'react';
+import {useState, useEffect} from 'react';
import Clock from './Clock.js';
function useTime() {
@@ -185,29 +213,32 @@ function useTime() {
export default function App() {
const time = useTime();
- return (
-
- );
+ return ;
}
```
-This works because during this last step, React only updates the content of `` with the new `time`. It sees that the ` ` appears in the JSX in the same place as last time, so React doesn't touch the ` `—or its `value`!
-## Epilogue: Browser paint {/*epilogue-browser-paint*/}
+Tämä toimii koska viimeisen vaiheen aikana, React päivittää vain `` tagin sisällön `time`:n arvolla. Se näkee, että ` ` JSX:ssä on samassa paikassa kuin viimeksi, joten React ei koske ` ` kenttään tai sen `value`:n!
+
+## Epilogi: Selaimen maalaus {/*epilogue-browser-paint*/}
+
+Kun renderöinti on valmis ja React on päivittänyt DOM:in, selain uudelleenmaalaa ruudun. Vaikka tämä prosessi tunnetaan "selaimen renderöintinä", viittaamme siihen "maalaamisena" sekaannuksien välttämiseksi tässä dokumentaatiossa.
After rendering is done and React updated the DOM, the browser will repaint the screen. Although this process is known as "browser rendering", we'll refer to it as "painting" to avoid confusion throughout the docs.
-
+
-* Any screen update in a React app happens in three steps:
- 1. Trigger
- 2. Render
- 3. Commit
-* You can use Strict Mode to find mistakes in your components
-* React does not touch the DOM if the rendering result is the same as last time
+- Mikä tahansa ruudunpäivitys React sovelluksessa tapahtuu kolmessa vaiheessa:
+ 1. Käynnistys
+ 2. Renderöinti
+ 3. Kommitointi
+- Voit käyttää Strict Modea löytääksesi virheitä komponenteistasi
+- React ei koske DOM:iin jos renderöinnin tulos on sama kuin viimeksi
-
diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md
index 45b60240b..61d8b2205 100644
--- a/src/content/learn/rendering-lists.md
+++ b/src/content/learn/rendering-lists.md
@@ -1,24 +1,24 @@
---
-title: Rendering Lists
+title: Listojen renderöinti
---
-You will often want to display multiple similar components from a collection of data. You can use the [JavaScript array methods](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array#) to manipulate an array of data. On this page, you'll use [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) and [`map()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map) with React to filter and transform your array of data into an array of components.
+Saatat usein haluta näyttää useita samanlaisia komponentteja datakokoelmasta. Voit käyttää [JavaScriptin listametodeja](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array#) manipuloidaksesi tietojoukkoja. Tällä sivulla tulet käyttämään [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) ja [`map()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map) metodeita Reactissa suodattaaksesi ja muuttaaksesi tietojoukon komponenttitaulukoksi.
-* How to render components from an array using JavaScript's `map()`
-* How to render only specific components using JavaScript's `filter()`
-* When and why to use React keys
+* Miten komponentteja renderöidään listasta käyttäen JavaScriptin `map()` metodia
+* Miten renderöidään tiettyjä komponentteja käyttäen JavaScriptin `filter()` metodia
+* Miksi ja milloin käyttää React key:ta
-## Rendering data from arrays {/*rendering-data-from-arrays*/}
+## Tietojen renderöinti taulukosta {/*rendering-data-from-arrays*/}
-Say that you have a list of content.
+Sanotaan, että sinulla on taulukko sisältöä.
```js
@@ -30,11 +30,11 @@ Say that you have a list of content.
```
-The only difference among those list items is their contents, their data. You will often need to show several instances of the same component using different data when building interfaces: from lists of comments to galleries of profile images. In these situations, you can store that data in JavaScript objects and arrays and use methods like [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) to render lists of components from them.
+Ainoa ero taulukon alkioiden välillä on niiden sisältö eli data. Usein täytyy näyttää useita ilmentymiä samasta komponentista eri datalla käyttöliittymiä rakentaesa: kommenttilistoista profiilikuvien gallerioihin. Näissä tilanteissa voit tallentaa datan JavaScriptin olioihin ja taulukoihin käyttämällä metodeja kuten `map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) ja [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) renderöidäksesi niistä komponenttilistan.
-Here’s a short example of how to generate a list of items from an array:
+Tässä lyhyt esimerkki miten luoda kohdelistaus tietojoukosta:
-1. **Move** the data into an array:
+1. **Siirrä** datat taulukkoon:
```js
const people = [
@@ -46,19 +46,19 @@ const people = [
];
```
-2. **Map** the `people` members into a new array of JSX nodes, `listItems`:
+1. **Mäppää** `people` kohteet uuteen taulukkoon `listItems` koostuen JSX:sta:
```js
const listItems = people.map(person => {person} );
```
-3. **Return** `listItems` from your component wrapped in a ``:
+3. **Palauta** `listItems` komponentistasi käärittynä `` sisään:
```js
return ;
```
-Here is the result:
+Tässä lopputulos:
@@ -85,7 +85,7 @@ li { margin-bottom: 10px; }
-Notice the sandbox above displays a console error:
+Huomaa hiekkalaatikko yllä, joka näyttää konsolivirheen:
@@ -93,11 +93,11 @@ Warning: Each child in a list should have a unique "key" prop.
-You'll learn how to fix this error later on this page. Before we get to that, let's add some structure to your data.
+Opit miten tämä virhe korjataan myöhemmin tällä sivulla. Ennen kuin menemme siihen, jäsennetään dataasi hieman.
-## Filtering arrays of items {/*filtering-arrays-of-items*/}
+## Taulukon tietojen suodattaminen {/*filtering-arrays-of-items*/}
-This data can be structured even more.
+Tätä dataa voidaan jäsentää vielä enemmän.
```js
const people = [{
@@ -121,11 +121,11 @@ const people = [{
}];
```
-Let's say you want a way to only show people whose profession is `'chemist'`. You can use JavaScript's `filter()` method to return just those people. This method takes an array of items, passes them through a “test” (a function that returns `true` or `false`), and returns a new array of only those items that passed the test (returned `true`).
+Sanotaan, että haluat näyttää vain henkilöt joiden ammatti on `'chemist'`. Voit käyttää JavaScriptin `filter()` metodia palauttaaksesi vain ne henkilöt. Tämä metodi ottaa talukon kohteista ja välittää ne "testin" läpi (funktion, joka palauttaa `true` tai `false`) ja palauttaa uuden taulukon sisältäen vain ne kohteet jotka läpäisiviät testin (palautti `true`).
-You only want the items where `profession` is `'chemist'`. The "test" function for this looks like `(person) => person.profession === 'chemist'`. Here's how to put it together:
+Haluat vain kohteet joissa `profession` on `'chemist'`. Tämä "testaus" funktio tälle näyttäisi seuraavalta `(person) => person.profession === 'chemist'`. Tässä kuinka se vielä kootaan:
-1. **Create** a new array of just “chemist” people, `chemists`, by calling `filter()` on the `people` filtering by `person.profession === 'chemist'`:
+1. **Luo** uusi taulukko `chemists` sisältäen vain "chemist" henkilöt kutsumalla `filter()` metodia `people` taulukossa suodattaen `person.profession === 'chemist'`:
```js
const chemists = people.filter(person =>
@@ -133,7 +133,7 @@ const chemists = people.filter(person =>
);
```
-2. Now **map** over `chemists`:
+1. Nyt **mäppää** `chemists`:
```js {1,13}
const listItems = chemists.map(person =>
@@ -151,7 +151,7 @@ const listItems = chemists.map(person =>
);
```
-3. Lastly, **return** the `listItems` from your component:
+1. Lopuksi, **palauta** `listItems` komponentistasi:
```js
return ;
@@ -244,29 +244,29 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-Arrow functions implicitly return the expression right after `=>`, so you didn't need a `return` statement:
+Nuolifunktiot implisiittisesti palauttavat lausekkeen heti `=>` jälkeen, joten et tarvitse `return` lausetta:
```js
const listItems = chemists.map(person =>
- ... // Implicit return!
+ ... // Implisiittinen palautus!
);
```
-However, **you must write `return` explicitly if your `=>` is followed by a `{` curly brace!**
+Kuitenkin, **sinun täytyy kirjoittaa `return` eksplisiittisesti jos `=>` jälkeen tulee `{` aaltosulje!**
```js
-const listItems = chemists.map(person => { // Curly brace
+const listItems = chemists.map(person => { // Aaltosulje
return ... ;
});
```
-Arrow functions containing `=> {` are said to have a ["block body".](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#function_body) They let you write more than a single line of code, but you *have to* write a `return` statement yourself. If you forget it, nothing gets returned!
+Nuolifunktiot, jotka sisältävät `=> {` sanotaan omaavan ["block body":n.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#function_body) Niissä voit kirjoittaa enemmän kuin yhden rivin koodia, mutta sinun *täytyy* kirjoittaa `return` lauseke. Jos unohdat sen, mitään ei palaudu!
-## Keeping list items in order with `key` {/*keeping-list-items-in-order-with-key*/}
+## Listojen pitäminen järjestyksessä käyttämällä `key`:ta {/*keeping-list-items-in-order-with-key*/}
-Notice that all the sandboxes above show an error in the console:
+Huomaa, että kaikki alla yllä olevat hiekkalaatikot näyttävät virheen konsolissa:
@@ -274,7 +274,7 @@ Warning: Each child in a list should have a unique "key" prop.
-You need to give each array item a `key` -- a string or a number that uniquely identifies it among other items in that array:
+Joudut antamaan jokaiselle taulukon kohteelle `key`:n -- merkkijonon tai numeron joka tunnistaa yksilöllisesti sen muista taulukon kohteista:
```js
...
@@ -282,13 +282,13 @@ You need to give each array item a `key` -- a string or a number that uniquely i
-JSX elements directly inside a `map()` call always need keys!
+JSX elementit suoraan `map()` kutsun sisällä tarvitsevat aina avaimet!
-Keys tell React which array item each component corresponds to, so that it can match them up later. This becomes important if your array items can move (e.g. due to sorting), get inserted, or get deleted. A well-chosen `key` helps React infer what exactly has happened, and make the correct updates to the DOM tree.
+Avaimet kertovat Reactille mitkä taulukon kohteet vastaavat mitäkin komponenttia, jotta se voi yhdistää ne myöhemmin. Tästä tulee tärkeää jos taulukon kohteet voivat liikkua (esim. suodatuksen seurauksena), kohteita lisätään tai poistetaan. Hyvin valittu `key` auttaa Reactia päättämään mitä oikeastaan on tapahtunut tehdäkseen oikeat päivitykset DOM-puuhun.
-Rather than generating keys on the fly, you should include them in your data:
+Sen sijaan, että avaimet luotaisiin lennosta, kannattaa sisällyttää ne datassasi:
@@ -374,11 +374,11 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-#### Displaying several DOM nodes for each list item {/*displaying-several-dom-nodes-for-each-list-item*/}
+#### Useiden DOM-kohteiden näyttäminen jokaikselle taulukon kohteelle {/*displaying-several-dom-nodes-for-each-list-item*/}
-What do you do when each item needs to render not one, but several DOM nodes?
+Mitä teet kun yhden kohteen täytyy renderlidä useampi DOM-kohde?
-The short [`<>...>` Fragment](/reference/react/Fragment) syntax won't let you pass a key, so you need to either group them into a single ``, or use the slightly longer and [more explicit `
` syntax:](/reference/react/Fragment#rendering-a-list-of-fragments)
+Lyhyt [`<>...>` Fragment](/reference/react/Fragment)-syntaksi ei anna sinun välittää avainta, joten joudut joko sisällyttämään ne ``:n sisälle, tai voit käyttää hieman pitempää ja [eksplisiittisempää `
` syntaksia:](/reference/react/Fragment#rendering-a-list-of-fragments)
```js
import { Fragment } from 'react';
@@ -393,46 +393,46 @@ const listItems = people.map(person =>
);
```
-Fragments disappear from the DOM, so this will produce a flat list of ``, ` `, `
`, ` `, and so on.
+Fragmentit häviävät DOM:sta, joten tämä tuottaa tasaisen listauksen elementeistä `
`, ` `, `
`, ` `, ja niin edelleen.
-### Where to get your `key` {/*where-to-get-your-key*/}
+### Mistä saat `key`:n {/*where-to-get-your-key*/}
-Different sources of data provide different sources of keys:
+Eri tietolähteet tarjoavat eri lähteet avaimille:
-* **Data from a database:** If your data is coming from a database, you can use the database keys/IDs, which are unique by nature.
-* **Locally generated data:** If your data is generated and persisted locally (e.g. notes in a note-taking app), use an incrementing counter, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) or a package like [`uuid`](https://www.npmjs.com/package/uuid) when creating items.
+* **Data tietokannasta:** Jos datasi tulee tietokannasta, voit käyttää tietokannan avaimia/ID:tä, jotka ovat luonnostaan uniikkeja.
+* **Paikallisesti luotu data:** Jos datasi on luotu ja tallennettu paikallisesti (esim. muistiinpanot muistiinpanosovelluksessa), käytä kasvavaa laskuria, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID):ta, tai a pakettia kuten [`uuid`](https://www.npmjs.com/package/uuid) kohteita luodessa.
-### Rules of keys {/*rules-of-keys*/}
+### Avainten säännöt {/*rules-of-keys*/}
-* **Keys must be unique among siblings.** However, it’s okay to use the same keys for JSX nodes in _different_ arrays.
-* **Keys must not change** or that defeats their purpose! Don't generate them while rendering.
+* **Avainten on oltava uniikkeja sen sisaruksiin nähden.** Kuitenkin, on sallittau käyttää samoja avaimia JSX kohteissa _eri_ taulukoissa.
+* **Avaimet eivät saa muuttua** tai se tuhoaa niiden koko tarkoituksen! Älä luo niitä kun renderöidään.
-### Why does React need keys? {/*why-does-react-need-keys*/}
+### Miksi React tarvitsee avaimia? {/*why-does-react-need-keys*/}
-Imagine that files on your desktop didn't have names. Instead, you'd refer to them by their order -- the first file, the second file, and so on. You could get used to it, but once you delete a file, it would get confusing. The second file would become the first file, the third file would be the second file, and so on.
+Kuvittele, että tiedostoilla työpöydälläsi ei olisi nimiä. Sen sijaan viittaisit niihin niiden järjestyksen perusteella -- ensimmäinen tiedosto, toinen tiedosto, ja niin edelleen. Voisit tottua siihen, mutta kun poistat tiedoston niin siitä tulisi sekavaa. Toisesta tiedostosta tulisi ensimmäinen, kolmannesta toinen, ja niin edelleen.
-File names in a folder and JSX keys in an array serve a similar purpose. They let us uniquely identify an item between its siblings. A well-chosen key provides more information than the position within the array. Even if the _position_ changes due to reordering, the `key` lets React identify the item throughout its lifetime.
+Tiedostonimet kansioissa ja JSX avaimet taulukossa palvelevat samantapaiseen tarkoitukseen. Sen avulla voidaan yksilöidä kohteet sen sisaruksista. Hyvin valittu avain tarjoaa enemmän tietoa kuin pelkän sijainnin taulukossa. Vaikka _sijainti_ muuttuisi uudelleenjärjestyksen seurauksena, `key`:n avulla React tunnistaa kohteet sen elinkaaren aikana.
-You might be tempted to use an item's index in the array as its key. In fact, that's what React will use if you don't specify a `key` at all. But the order in which you render items will change over time if an item is inserted, deleted, or if the array gets reordered. Index as a key often leads to subtle and confusing bugs.
+Saatat tuntea houkutusta käyttää kohteen indeksiä taulukossa sen avaimena. Itse asiassa, sitä React käyttää kun et määrittele `key`:ta ollenkaan. Kohteiden järjestys muuttuu ajan kuluessa, jos kohteita lisätään, poistetaan tai jos taulukko järjestetään uudelleen. Indeksi avaimena johtaa usein hienovaraisiin ja sekaviin bugeihin.
-Similarly, do not generate keys on the fly, e.g. with `key={Math.random()}`. This will cause keys to never match up between renders, leading to all your components and DOM being recreated every time. Not only is this slow, but it will also lose any user input inside the list items. Instead, use a stable ID based on the data.
+Vastaavasti, älä luo avaimia lennosta. esim `key={Math.random()}`. Tämän seurauksena avaimet eivät koskaan vastaa toisiaan renderöintien välillä johtaen jokaisen komponentin ja DOM-kohteen uudelleenluontiin joka kerta. Tämä ei ole ainoastaan hidasta, mutta se myös unohtaa käyttäjän syötteen listan kohteissa. Käytä sen sijaan vakaita ID:ta datan pohjalta.
-Note that your components won't receive `key` as a prop. It's only used as a hint by React itself. If your component needs an ID, you have to pass it as a separate prop: ` `.
+Huomaa, että komponenttisi eivät vastaanota `key`:ta propsina. React käyttää sitä vinkkinä vain itselleen. Jos komponenttisi tarvitsee ID:n, täytyy se välittää erillisenä propsina: ` `.
-On this page you learned:
+Tällä sivulla olet oppinut:
-* How to move data out of components and into data structures like arrays and objects.
-* How to generate sets of similar components with JavaScript's `map()`.
-* How to create arrays of filtered items with JavaScript's `filter()`.
-* Why and how to set `key` on each component in a collection so React can keep track of each of them even if their position or data changes.
+* Miten siirtää dataa komponenteista ulos tietorakenteisiin kuten taulukoihin ja olioihin.
+* Miten luodaan joukkoja samanlaisia komponentteja käyttämällä JavaScript:n `map()` metodia.
+* Miten luodaan taulukkoja suodatetuista kohteista käyttämällä JavaScript:n `filter()` metodia.
+* Miksi ja miten asetetaan `key` jokaisen kokoelman komponentille, jotta React voi pitää kohteita yllä vaikka niiden sijainti tai data muuttuisi.
@@ -440,11 +440,11 @@ On this page you learned:
-#### Splitting a list in two {/*splitting-a-list-in-two*/}
+#### Listan jakaminen kahteen {/*splitting-a-list-in-two*/}
-This example shows a list of all people.
+Tämä esimerkki näyttää listan kaikista henkilöistä.
-Change it to show two separate lists one after another: **Chemists** and **Everyone Else.** Like previously, you can determine whether a person is a chemist by checking if `person.profession === 'chemist'`.
+Muuta se näyttämään kaksi erillistä listaa toinen toisensa jälkeen: **Chemists** ja **Everyone Else**. Kuten aiemmin, voit määritellä mikäli henkilö on kemisti tarkistamalla jos `person.profession === 'chemist'`.
@@ -535,7 +535,7 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-You could use `filter()` twice, creating two separate arrays, and then `map` over both of them:
+Voit myös käyttää `filter()` metodia kahdesti, luoden kaksi erillistä taulukkoa ja sitten mäppäät molemmat niistä:
@@ -648,9 +648,9 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-In this solution, the `map` calls are placed directly inline into the parent `` elements, but you could introduce variables for them if you find that more readable.
+Tässä ratkaisussa, `map` kutsut sijoitetaan suoraan samalle riville `` elementteihin, mutta voit esitellä muuttujia niille mikäli koet sen luettavempana.
-There is still a bit duplication between the rendered lists. You can go further and extract the repetitive parts into a `` component:
+Tässä on vielä hieman koodin toistoa renderöityjen listojen kesken. Voit mennä pidemmälle ja siirtää toistuvan koodin `` komponenttiin:
@@ -762,9 +762,9 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-A very attentive reader might notice that with two `filter` calls, we check each person's profession twice. Checking a property is very fast, so in this example it's fine. If your logic was more expensive than that, you could replace the `filter` calls with a loop that manually constructs the arrays and checks each person once.
+Tarkkaavainen lukija saattaa huomata, että kahden `filter` kutsun takia tarkistamme jokaisen henkilön ammatin kahdesti. Propertyn tarkistaminen on hyvin nopeaa, joten tässä esimerkissä se ei haittaa. Jos logiikkasi kuitenkin olisi raskaampaa kuin tässä, voisit korvata `filter` kutsut silmukalla, joka manuaalisesti luo taulukot ja tarkistaa henkilön vain kerran.
-In fact, if `people` never change, you could move this code out of your component. From React's perspective, all that matters is that you give it an array of JSX nodes in the end. It doesn't care how you produce that array:
+Itse asiassa, jos `people` ei koskaan muutu, voisit siirtää tämän koodin pois komponentistasi. Reactin näkökulmasta riittää, että annat sille taulukon JSX-kohteita. Ei ole merkitystä miten luot kyseisen taulukon:
@@ -882,13 +882,13 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-#### Nested lists in one component {/*nested-lists-in-one-component*/}
+#### Sisäkkäiset listat yhdessä komponenetissa {/*nested-lists-in-one-component*/}
-Make a list of recipes from this array! For each recipe in the array, display its name as an `` and list its ingredients in a ``.
+Tee lista resepteista tästä taulukosta! Näytä jokaiselle reseptille taulukossa sen otsikko `` elementtinä ja listaa sen ainesosat `` elementissä.
-This will require nesting two different `map` calls.
+Tämä vaatii kaksi sisäkkäistä `map` kutsua.
@@ -926,7 +926,7 @@ export const recipes = [{
-Here is one way you could go about it:
+Tässä yksi tapa, jota voit käyttää:
@@ -972,13 +972,13 @@ export const recipes = [{
-Each of the `recipes` already includes an `id` field, so that's what the outer loop uses for its `key`. There is no ID you could use to loop over ingredients. However, it's reasonable to assume that the same ingredient won't be listed twice within the same recipe, so its name can serve as a `key`. Alternatively, you could change the data structure to add IDs, or use index as a `key` (with the caveat that you can't safely reorder ingredients).
+Jokainen `recipes` valmiiksi sisältää `id` kentän, joten ulompi silmukka käyttää sitä sen `key`:na. Ainesosia läpikäydessä ei ole ID:ta jota voisit käyttää. Kuitenkin on kohtuullista olettaa, että samoja ainesosia ei listata kahdesti samassa reseptissa, joten sen nimi voi toimia sen `key`:na. Vaihtoehtoisesti, voit muuttaa tietorakennetta sisällyttämään ID:n tai käyttää sen indeksiä `key`:na (sillä varauksella, että et voi turvallisesti järjestää ainesosia uudelleen).
-#### Extracting a list item component {/*extracting-a-list-item-component*/}
+#### Irrota lista-elementti omaan komponenttiin {/*extracting-a-list-item-component*/}
-This `RecipeList` component contains two nested `map` calls. To simplify it, extract a `Recipe` component from it which will accept `id`, `name`, and `ingredients` props. Where do you place the outer `key` and why?
+Tämä `RecipeList` komponentti sisältää kaksi `map` kutsua. Yksinkertaistaaksesi sen, luo `Recipe` komponentti siitä joka vastaanottaa `id`, `name` ja `ingredients` propsit. Mihin sijoittaisit ulomman `key`:n ja miksi?
@@ -1026,7 +1026,7 @@ export const recipes = [{
-You can copy-paste the JSX from the outer `map` into a new `Recipe` component and return that JSX. Then you can change `recipe.name` to `name`, `recipe.id` to `id`, and so on, and pass them as props to the `Recipe`:
+Voit kopioida JSX-koodin ulommasta `map`:sta uuteen `Recipe` komponenttiin ja palauttaa sen JSX:n. Voit sitten muuttaa `recipe.name` lukemaan `name`, `recipe.id` lukemaan `id`, ja niin edelleen ja välittää ne propseina `Recipe` komponentille:
@@ -1078,15 +1078,15 @@ export const recipes = [{
-Here, ` ` is a syntax shortcut saying "pass all properties of the `recipe` object as props to the `Recipe` component". You could also write each prop explicitly: ` `.
+Tässä ` ` on lyhytsyntaksi joka "välittää kaikki propertyt `recipe` oliosta propseina `Recipe` komponentille". Voisit myös kirjoittaa jokaisen propsin eksplisiittisesti: ` `.
-**Note that the `key` is specified on the `` itself rather than on the root `` returned from `Recipe`.** This is because this `key` is needed directly within the context of the surrounding array. Previously, you had an array of `
`s so each of them needed a `key`, but now you have an array of `
`s. In other words, when you extract a component, don't forget to leave the `key` outside the JSX you copy and paste.
+**Huomaa, että `key` on määritelty `` komponenttiin eikä `Recipe` komponentin palauttamaan juuri-`` elementtiin.** Tämä siksi koska `key` tarvitaan suoraan ympäröivän taulukon yhteydessä. Aiemmin sinulla oli taulukko `
` elementtejä, joten jokainen niistä tarvitsi `key`:n, mutta nyt sinulla on taulukko `
`:ja. Toisin sanoen, kun irrotat komponentin koodista, älä unohda siirtää `key`:ta kopioidun JSX koodin ulkopuolelle.
-#### List with a separator {/*list-with-a-separator*/}
+#### Listat erottimella {/*list-with-a-separator*/}
-This example renders a famous haiku by Katsushika Hokusai, with each line wrapped in a `` tag. Your job is to insert an `
` separator between each paragraph. Your resulting structure should look like this:
+Tämä esimerkki renderöi kuuluisan Katsushika Hokusain haikun, jokaisen rivin ollessa kääritty `` tagin sisään. Tehtäväsi on sijoittaa `
` erotin jokaisen kappaleen jälkeen. Lopputuloksen rakennelman pitäisi näyttää tältä:
```js
@@ -1098,7 +1098,7 @@ This example renders a famous haiku by Katsushika Hokusai, with each line wrappe
```
-A haiku only contains three lines, but your solution should work with any number of lines. Note that ` ` elements only appear *between* the `` elements, not in the beginning or the end!
+Haiku sisältää vain kolme riviä, mutta ratkaisusi tulisi toimia minkä tahansa rivimäärän kanssa. Huomaa, että `
` elementit näkyvät `` elementtien *välissä*, ei vain alussa tai lopussa!
@@ -1141,17 +1141,17 @@ hr {
-(This is a rare case where index as a key is acceptable because a poem's lines will never reorder.)
+(Tämä on harvinainen tilanne missä indeksi avaimena on hyväksyttävää koska runon rivit eivät koskaan järjesty uudelleen.)
-You'll either need to convert `map` to a manual loop, or use a fragment.
+Sinun täytyy joko muuttaa `map` manuaaliseksi silmukaksi tai käyttää fragmentia.
-You can write a manual loop, inserting ` ` and `...
` into the output array as you go:
+Voit kirjoittaa manuaalisen silmukan, sijoittaen ` ` ja `...
` palautustaulukoon edetessäsi:
@@ -1206,9 +1206,9 @@ hr {
-Using the original line index as a `key` doesn't work anymore because each separator and paragraph are now in the same array. However, you can give each of them a distinct key using a suffix, e.g. `key={i + '-text'}`.
+Alkuperäisen rivin indeksin käyttäminen `key`.na ei enää toimi sillä erottimet ja kappaleet ovat nyt samassa taulukossa. Kuitenkin, voit antaa niille erillisen avaimen käyttämällä jälkiliitettä, esim. `key={i + '-text'}`.
-Alternatively, you could render a collection of fragments which contain ` ` and `...
`. However, the `<>...>` shorthand syntax doesn't support passing keys, so you'd have to write `` explicitly:
+Vaihtoehtoisesti voit renderöidä kokoelman fragmenteja, jotka sisältävät ` ` ja `...
` tagit. Kuitenkin `<>...>` lyhytsyntaksi ei tue avainten välittämistä, joten joutuisit kirjoittamaan ``:n eksplisiittisesti:
@@ -1254,7 +1254,7 @@ hr {
-Remember, fragments (often written as `<> >`) let you group JSX nodes without adding extra ``s!
+Muista, fragmentit (useiten kirjoitettuna `<> >`) antavat sinun ryhmittää JSX-kohteita lisäämättä ylimääräisiä `
`-elementtejä!
diff --git a/src/content/learn/responding-to-events.md b/src/content/learn/responding-to-events.md
index 4450c4613..bf13a6eed 100644
--- a/src/content/learn/responding-to-events.md
+++ b/src/content/learn/responding-to-events.md
@@ -1,24 +1,24 @@
---
-title: Responding to Events
+title: Tapahtumiin vastaaminen
---
-React lets you add *event handlers* to your JSX. Event handlers are your own functions that will be triggered in response to interactions like clicking, hovering, focusing form inputs, and so on.
+React antaa sinun lisätä *tapahtumakäsittelijöitä* JSX:sssä. Tapahtumakäsittelijät ovat omia funktioitasi, joita kutsutaan vastauksena vuorovaikutuksiin kuten klikkauseen, hoveriin, lomakkeiden kohteiden focusointiin, jne.
-* Different ways to write an event handler
-* How to pass event handling logic from a parent component
-* How events propagate and how to stop them
+* Eri tavat kirjoittaa tapahtumakäsittelijä
+* Miten välittää tapahtumakäsittelijän logiikka pääkomponentista
+* Miten tapahtumat leviävät ja miten sen voi estää
-## Adding event handlers {/*adding-event-handlers*/}
+## Tapahtumakäsittelijöiden lisääminen {/*adding-event-handlers*/}
-To add an event handler, you will first define a function and then [pass it as a prop](/learn/passing-props-to-a-component) to the appropriate JSX tag. For example, here is a button that doesn't do anything yet:
+Lisätäksesi tapahtumakäsittelijän, täytyy ensiksi määritellä funktio ja sitten [välittää se propsina](/learn/passing-props-to-a-component) sopivalle JSX tagille. Esimerkiksi, tässä on painike, joka ei tee vielä mitään:
@@ -34,11 +34,11 @@ export default function Button() {
-You can make it show a message when a user clicks by following these three steps:
+Voit laittaa sen näyttämään viestin kun käyttäjä klikkaa tekemällä nämä kolme vaihetta:
-1. Declare a function called `handleClick` *inside* your `Button` component.
-2. Implement the logic inside that function (use `alert` to show the message).
-3. Add `onClick={handleClick}` to the `
` JSX.
+1. Määritä funktio nimeltään `handleClick` komponentin `Button` *sisällä*.
+2. Toteuta logiikka funktion sisällä (käytä `alert` funktiota näyttääksesi viestin).
+3. Lisää `onClick={handleClick}` `` tagiin JSX:ssä.
@@ -62,14 +62,14 @@ button { margin-right: 10px; }
-You defined the `handleClick` function and then [passed it as a prop](/learn/passing-props-to-a-component) to ``. `handleClick` is an **event handler.** Event handler functions:
+Määrittelit `handleClick` funktion ja [välitit sen propsina](/learn/passing-props-to-a-component) ``:lle. `handleClick` on **tapahtumaksäittelijä**. Tapahtumakäsittelijäfunktiot:
-* Are usually defined *inside* your components.
-* Have names that start with `handle`, followed by the name of the event.
+* ovat useimmiten määritelty komponenttien *sisällä*.
+* alkavat sanalla `handle`, jonka jälkeen nimeen tulee tapahtuman nimi.
-By convention, it is common to name event handlers as `handle` followed by the event name. You'll often see `onClick={handleClick}`, `onMouseEnter={handleMouseEnter}`, and so on.
+Tavanomaisesti tapahtumakäsittelijät alkavat sanalla `handle` ja sisältävät tapahtuman nimen. Näet usein `onClick={handleClick}`, `onMouseEnter={handleMouseEnter}`, ja niin edelleen.
-Alternatively, you can define an event handler inline in the JSX:
+Vaihtoehtoisesti voit määritellä tapahtumakäsittelijän samalla rivillä JSX:ssä.
```jsx
```
-Or, more concisely, using an arrow function:
+Tai tiiviimmin nuolifunktioilla:
```jsx
{
@@ -85,54 +85,54 @@ Or, more concisely, using an arrow function:
}}>
```
-All of these styles are equivalent. Inline event handlers are convenient for short functions.
+Kaikki nämä tyylit vastaavat toisiaan. Samalla rivillä olevat tapahtumakäsittelijät ovat käteviä lyhyihin funktioihin.
-Functions passed to event handlers must be passed, not called. For example:
+Tapahtumakäsittelijöihin annetut funktiot täytyy välitää, niitä ei pidä kutsua. Esimerkiksi:
-| passing a function (correct) | calling a function (incorrect) |
-| -------------------------------- | ---------------------------------- |
+| funktion välittäminen (oikein) | funktion kutsuminen (väärin) |
+|----------------------------------|------------------------------------|
| `` | `` |
-The difference is subtle. In the first example, the `handleClick` function is passed as an `onClick` event handler. This tells React to remember it and only call your function when the user clicks the button.
+Ero on hienovarainen. Ensimmäisessä esimerkissä `handleClick` funktio välitetään `onClick` tapahtumakäsittelijäksi. Tämä kertoo Reactille, että sen täytyy muistaa se ja kutsua sitä vain kun käyttäjä klikkaa painiketta.
-In the second example, the `()` at the end of `handleClick()` fires the function *immediately* during [rendering](/learn/render-and-commit), without any clicks. This is because JavaScript inside the [JSX `{` and `}`](/learn/javascript-in-jsx-with-curly-braces) executes right away.
+Toisessa esimerkissä `handleClick()` lopussa oleva `()` kutsuu funktiota *heti* [renderöinnin](/learn/render-and-commit) aikana ilman yhtään klikkausta. Näin tapahtuu, koska JSX aaltosulkeiden välissä [`{` ja `}`](/learn/javascript-in-jsx-with-curly-braces) oleva JavaScript suoritetaan heti.
-When you write code inline, the same pitfall presents itself in a different way:
+Kun kirjoitat koodia samalle riville, sama sudenkuoppa esiintyy uudelleen eri tavalla:
-| passing a function (correct) | calling a function (incorrect) |
-| --------------------------------------- | --------------------------------- |
+| funktion välittäminen (oikein) | funktion kutsuminen (väärin) |
+|-----------------------------------------|-----------------------------------|
| ` alert('...')}>` | `` |
-Passing inline code like this won't fire on click—it fires every time the component renders:
+Tällä tavoin annettua koodia ei kutsuta klikkauksen yhteydessä. Sitä kutsutaan joka kerta kun komponentti renderöidään:
```jsx
-// This alert fires when the component renders, not when clicked!
+// Tämä ilmoitus kutsutaan kun komponentti renderöidään, ei klikattaessa!
```
-If you want to define your event handler inline, wrap it in an anonymous function like so:
+Jos haluat määritellä tapahtumakäsittelijän samalla rivillä, kääri se anonyymiin funktioon tällä tavoin:
```jsx
alert('You clicked me!')}>
```
-Rather than executing the code inside with every render, this creates a function to be called later.
+Sen sijaan, että koodi suoritettaisiin joka renderöinnin yhteydessä, tämä luo uuden funktion myöhemmin kutsuttavaksi.
-In both cases, what you want to pass is a function:
+Molemmissa tilanteissa välität funktion:
-* `` passes the `handleClick` function.
-* ` alert('...')}>` passes the `() => alert('...')` function.
+* `` välittää `handleClick` funktion.
+* ` alert('...')}>` välittää `() => alert('...')` funktion.
-[Read more about arrow functions.](https://javascript.info/arrow-functions-basics)
+[Lue lisää nuolifunktioista.](https://javascript.info/arrow-functions-basics)
-### Reading props in event handlers {/*reading-props-in-event-handlers*/}
+### Propsien lukeminen tapahtumakäsittelijöissä {/*reading-props-in-event-handlers*/}
-Because event handlers are declared inside of a component, they have access to the component's props. Here is a button that, when clicked, shows an alert with its `message` prop:
+Sillä tapahtumakäsittelijät ovat määritelty komponentin sisällä, niillä on pääsy komponenttien propseihin. Tässä on painike, joka klikattaessa näyttää `message` prosin ilmoituksena:
@@ -165,13 +165,13 @@ button { margin-right: 10px; }
-This lets these two buttons show different messages. Try changing the messages passed to them.
+Näin nämä kaksi painiketta voivat näyttää eri viestejä. Kokeile muuttaa niille välitettyjä viestejä.
-### Passing event handlers as props {/*passing-event-handlers-as-props*/}
+### Tapahtumakäsittelijöiden välittäminen propseina {/*passing-event-handlers-as-props*/}
-Often you'll want the parent component to specify a child's event handler. Consider buttons: depending on where you're using a `Button` component, you might want to execute a different function—perhaps one plays a movie and another uploads an image.
+Usein haluat pääkomponentin pystyä määritellä alakomponentin tapahtumakäsittelijän. Esimerkiksi painikkeet: riippuen missä käytät `Button` komponenttia, saatat haluta kutsua eri funktiota. Ehkäpä yksi toistaa videota ja toinen lähettää kuvan palvelimelle.
-To do this, pass a prop the component receives from its parent as the event handler like so:
+Voit tehdä tämän välittämällä tapahtumakäsittelijän propsina alakomponentille:
@@ -220,22 +220,23 @@ button { margin-right: 10px; }
-Here, the `Toolbar` component renders a `PlayButton` and an `UploadButton`:
-- `PlayButton` passes `handlePlayClick` as the `onClick` prop to the `Button` inside.
-- `UploadButton` passes `() => alert('Uploading!')` as the `onClick` prop to the `Button` inside.
+Tässä, `Toolbar` komponentti renderöi `PlayButton` komponentin sekä `UploadButton` komponentin:
-Finally, your `Button` component accepts a prop called `onClick`. It passes that prop directly to the built-in browser `` with `onClick={onClick}`. This tells React to call the passed function on click.
+- `PlayButton` välittää `handlePlayClick` funktion `onClick` propsina `Button`:lle.
+- `UploadButton` välittää `() => alert('Uploading!')` funktion `onClick` propsina `Button`:lle.
-If you use a [design system](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969), it's common for components like buttons to contain styling but not specify behavior. Instead, components like `PlayButton` and `UploadButton` will pass event handlers down.
+Lopuksi, `Button` komponenttisi hyväksyy `onClick` propsin. Se välittää propsin suoraan selaimen sisäänrakennettuun `` elementtiin `onClick={onClick}` koodilla. Tämä kertoo Reactille, että kutsuu välitettyä funktiota klikkauksen yhteydessä.
-### Naming event handler props {/*naming-event-handler-props*/}
+Jos käytät [design system:iä](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969), on yleistä komponenttien kuten painikkeiden sisältää tyylit mutta ei käyttäytymistä. Sen sijaan komponentit kuten `PlayButton` ja `UploadButton` välittävät tapahtumakäsittelijät alaspäin.
-Built-in components like `` and `` only support [browser event names](/reference/react-dom/components/common#common-props) like `onClick`. However, when you're building your own components, you can name their event handler props any way that you like.
+### Tapahtumakäsittelijän propsien nimeäminen {/*naming-event-handler-props*/}
-By convention, event handler props should start with `on`, followed by a capital letter.
+Sisäänrakennetut elementit kuten `
` ja `` tukevat ainoastaan [selaimen tapahtumien nimiä](/reference/react-dom/components/common#common-props) kuten `onClick`. Kuitenkin, kun rakennat omia komponenttejasi, voit nimetä niiden tapahtumakäsittelijöiden propsit miten haluat.
-For example, the `Button` component's `onClick` prop could have been called `onSmash`:
+Tavanomaisesti, tapahtumakäsittelijän propsien kuuluisi alkaa sanalla `on`, ja jatkua isolla kirjaimella.
+
+Esimerkiksi, `Button` komponentin `onClick` propsi voitaisiin kutusua `onSmash`:
@@ -268,9 +269,9 @@ button { margin-right: 10px; }
-In this example, `
` shows that the browser `` (lowercase) still needs a prop called `onClick`, but the prop name received by your custom `Button` component is up to you!
+Tässä esimerkissä, `` kertoo, että selaimen `` elementti (pienin kirjaimin) tarvitsee silti propsin nimeltään `onClick`, mutta kustomoidun `Button` komponentin vastaanottaman propsin nimi voi olla mikä tahansa!
-When your component supports multiple interactions, you might name event handler props for app-specific concepts. For example, this `Toolbar` component receives `onPlayMovie` and `onUploadImage` event handlers:
+Kun komponenttisi tukee useampia interaktioita, saatat nimetä tapahtumakäsittelijöiden propsit sovelluskohtaisin konseptein. Esimerkiksi tämä `Toolbar` komponentti vastaanottaa `onPlayMovie` sekä `onUploadImage` tapahtumakäsittelijät:
@@ -312,19 +313,19 @@ button { margin-right: 10px; }
-Notice how the `App` component does not need to know *what* `Toolbar` will do with `onPlayMovie` or `onUploadImage`. That's an implementation detail of the `Toolbar`. Here, `Toolbar` passes them down as `onClick` handlers to its `Button`s, but it could later also trigger them on a keyboard shortcut. Naming props after app-specific interactions like `onPlayMovie` gives you the flexibility to change how they're used later.
-
+Huomaa, miten `App` komponentin ei tarvitse tietää *mitä* `Toolbar` tekee sen `onPlayMovie` tai `onUploadImage` tapahtumakäsittelijöillä. Se on `Toolbar` komponentin toteutusyksityiskohta. Tässä, `Toolbar` välittää ne `Button`:nien `onClick` käsittelijöinä, mutta se voisi myöhemmin myös kutsua niitä pikanäppäimestä. Propsien nimeäminen sovelluskohtaisten vuorovaikutusten kautta, kuten `onPlayMovie`, antaa joustavuuden muuttaa niitä myöhemmin.
+
-Make sure that you use the appropriate HTML tags for your event handlers. For example, to handle clicks, use [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) instead of ``. Using a real browser `
` enables built-in browser behaviors like keyboard navigation. If you don't like the default browser styling of a button and want to make it look more like a link or a different UI element, you can achieve it with CSS. [Learn more about writing accessible markup.](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML)
+Varmista, että käytät asianmukaisia HTML-tageja tapahtumankäsittelijöillesi. Esimerkiksi klikkausten käsittelyyn käytä [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) -elementtiä sen sijaan, että käyttäisit ``. Todellisen selaimen `
` -elementin käyttäminen mahdollistaa sisäänrakennetut selaimen toiminnot, kuten näppäimistönavigoinnin. Jos et pidä oletusarvoisesta painikkeen ulkoasusta ja haluat muokata sitä näyttämään enemmän linkiltä tai erilaiselta käyttöliittymäelementiltä, voit saavuttaa sen CSS:n avulla. [Lue lisää saavutettavan merkinnän kirjoittamisesta.](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML)
-## Event propagation {/*event-propagation*/}
+## Tapahtuman leviäminen {/*event-propagation*/}
-Event handlers will also catch events from any children your component might have. We say that an event "bubbles" or "propagates" up the tree: it starts with where the event happened, and then goes up the tree.
+Komponenttisi tapahtumankäsittelijät nappaavat tapahtumia myös alakomponenteista. Tätä usein kutsutaan "kuplimiseksi" tai "propagoinniksi": se alkaa sieltä missä tapahtuma esiintyi ja nousee puussa ylemmäs.
-This `` contains two buttons. Both the `
` *and* each button have their own `onClick` handlers. Which handlers do you think will fire when you click a button?
+Tämä `
` sisältää kaksi painiketta. Sekä `
` tagi *että* painikkeet omaavat ikioman `onClick` käsittelijän. Mitä arvelet mitä tapahtumakäsittelijää kutsutaan, kun painiketta klikataan?
@@ -355,19 +356,19 @@ button { margin: 5px; }
-If you click on either button, its `onClick` will run first, followed by the parent `
`'s `onClick`. So two messages will appear. If you click the toolbar itself, only the parent `
`'s `onClick` will run.
+Jos klikkaat jompaa kumpaa painiketta, sen `onClick` suoritetaan ensin, jonka jälkeen `
` tagin `onClick`. Joten kaksi viestiä tulee näkyviin. Jos klikkaat työkalupalkkia vain `
`:n `onClick` suoritetaan.
-All events propagate in React except `onScroll`, which only works on the JSX tag you attach it to.
+Kaikki tapahtumat propagoituvat Reactissa paitsi `onScroll`, joka toimii vain siinä JSX tagissa johon sen liität.
-### Stopping propagation {/*stopping-propagation*/}
+### Propagoinnin pysäyttäminen {/*stopping-propagation*/}
-Event handlers receive an **event object** as their only argument. By convention, it's usually called `e`, which stands for "event". You can use this object to read information about the event.
+Tapahtumakäsittelijät vastaanottavat **tapahtumaolion** niiden ainoana argumenttina. Tavanomaisesti sitä usein kutsutaan `e` kirjaimella, joka on lyhenne sanasta "event". Voit käyttää tätä oliota lukeaksesi tietoa tapahtumasta.
-That event object also lets you stop the propagation. If you want to prevent an event from reaching parent components, you need to call `e.stopPropagation()` like this `Button` component does:
+Tämä tapahtumaolio mahdollistaa myös tapahtuman propagoinnin estämisen. Jos haluat estää tapahtuman propagoinnin pääkomponenteille, kutsu `e.stopPropagation()` funktiota kuten tämä `Button` komponentti tekee:
@@ -409,43 +410,43 @@ button { margin: 5px; }
-When you click on a button:
+Kun klikkaat painiketta:
-1. React calls the `onClick` handler passed to `
`.
-2. That handler, defined in `Button`, does the following:
- * Calls `e.stopPropagation()`, preventing the event from bubbling further.
- * Calls the `onClick` function, which is a prop passed from the `Toolbar` component.
-3. That function, defined in the `Toolbar` component, displays the button's own alert.
-4. Since the propagation was stopped, the parent ``'s `onClick` handler does *not* run.
+1. React kutsuu `
` tagille annettua `onClick` käsittelijää.
+2. Tämä `Button`:ssa määritelty käsittelijä tekee seuraavat asiat:
+ * Kutsuu `e.stopPropagation()` funktiota, estäen tapahtuman kuplimisen.
+ * Kutsuu `onClick` funktiota, joka on `Toolbar` komponentista välitetty propsi.
+3. `Toolbar` komponentissa määritelty funktio näyttää painikkeen oman ilmoituksen.
+4. Sillä propagointi on pysäytetty, `` tagin `onClick` käsittelijää ei suoriteta.
-As a result of `e.stopPropagation()`, clicking on the buttons now only shows a single alert (from the `
`) rather than the two of them (from the `` and the parent toolbar ``). Clicking a button is not the same thing as clicking the surrounding toolbar, so stopping the propagation makes sense for this UI.
+`e.stopPropagation()` funktion tuloksena painikkeiden klikkaaminen näyttää vain yhden ilmoituksen (`button`:sta) kahden ilmoituksen sijaan (`
`:sta sekä ``:sta). Painikkeen klikkaaminen ei ole sama asia kuin ympäröivä työkalupalkki, joten propagoinnin pysäyttäminen on järkevää tälle UI:lle.
-#### Capture phase events {/*capture-phase-events*/}
+#### Nappaa tapahtumavaiheet {/*capture-phase-events*/}
-In rare cases, you might need to catch all events on child elements, *even if they stopped propagation*. For example, maybe you want to log every click to analytics, regardless of the propagation logic. You can do this by adding `Capture` at the end of the event name:
+Harvinaisissa tapauksissa saatat haluta napata kaikki lapsielementtien tapahtumat, *vaikka ne olisivat estäneet propagoinnin*. Esimerkiksi, ehkäpä haluat kerätä analytiikkatietoja jokaisesta klikkauksesta, riippumatta propagointilogiikasta. Voit tehdä tämän lisäämällä `Capture` tapahtumanimen perään:
```js
- { /* this runs first */ }}>
+
{ /* suoritetaan ensin */ }}>
e.stopPropagation()} />
e.stopPropagation()} />
```
-Each event propagates in three phases:
+Jokainen tapahtuma propagoituu kolmaessa vaiheessa:
-1. It travels down, calling all `onClickCapture` handlers.
-2. It runs the clicked element's `onClick` handler.
-3. It travels upwards, calling all `onClick` handlers.
+1. Se kulkee alaspäin, kutsuen kaikki `onClickCapture` käsittelijät.
+2. Se suorittaa klikatun elementin `onClick` käsittelijän.
+3. Se kulkee ylöspäin, kutsuen kaikki `onClick` käsittelijät.
-Capture events are useful for code like routers or analytics, but you probably won't use them in app code.
+Tapahtumien nappaaminen on kätevää koodille kuten reitittimille taikka analytiikalle, mutta et todennäköisesti tule käyttämään sitä sovelluskoodissa.
-### Passing handlers as alternative to propagation {/*passing-handlers-as-alternative-to-propagation*/}
+### Käsittelijöiden välittäminen vaihtoehtona propagoinnille {/*passing-handlers-as-alternative-to-propagation*/}
-Notice how this click handler runs a line of code _and then_ calls the `onClick` prop passed by the parent:
+Huomaa kuinka tämä klikkauskäsittelijä suorittaa yhden rivin koodia _ja sitten_ kutsuu välitettyä `onClick` propsia:
```js {4,5}
function Button({ onClick, children }) {
@@ -460,13 +461,13 @@ function Button({ onClick, children }) {
}
```
-You could add more code to this handler before calling the parent `onClick` event handler, too. This pattern provides an *alternative* to propagation. It lets the child component handle the event, while also letting the parent component specify some additional behavior. Unlike propagation, it's not automatic. But the benefit of this pattern is that you can clearly follow the whole chain of code that executes as a result of some event.
+Voisit halutessasi lisätä lisää koodia tähän käsittelijään ennen `onClick` tapahtumakäsittelijän kutsumista. Tämä tapa mahdollistaa *vaihtoehdon* propagoinnille. Sen avulla alakomponentit käsittelevät tapahtuman, silti antaen pääkomponenttien määritellä lisäkäyttäytymisiä. Toisin kuin propagointi, se ei ole automaattista. Kuitenkin tällä tavalla voit selkeästi seurata koko koodiketjua, jota kutsutaan jonkin tapahtuman seurauksena.
-If you rely on propagation and it's difficult to trace which handlers execute and why, try this approach instead.
+Jos nojaat propagointiin ja on hankalaa jäljittää mikä käsittelijä suoritetaan ja miksi, kokeile tätä tapaa sen sijaan.
-### Preventing default behavior {/*preventing-default-behavior*/}
+### Oletustoiminnon estäminen {/*preventing-default-behavior*/}
-Some browser events have default behavior associated with them. For example, a `
);
}
@@ -679,9 +680,9 @@ export default function App() {
-First, you need to add the event handler, like ``.
+Ensiksi, sinun täytyy lisätä tapahtumakäsittelijä, tällä tavoin ``.
-However, this introduces the problem of the incrementing counter. If `onChangeColor` does not do this, as your colleague insists, then the problem is that this event propagates up, and some handler above does it. To solve this problem, you need to stop the propagation. But don't forget that you should still call `onChangeColor`.
+Tämä kuitenkin luo ongelman kasvavasta luvusta. Jos `onChangeColor` ei tee tätä, kuten kollegasi niin väittää, silloin ongelma on, että tämä tapahtuma propagoituu ylöspäin ja jokin muu käsittelijä tekee sen. Ongelman ratkaisemiseksi, sinun täytyy estää propagointi. Älä unohda kutsua `onChangeColor` funktiota.
@@ -694,7 +695,7 @@ export default function ColorSwitch({
e.stopPropagation();
onChangeColor();
}}>
- Change color
+ Vaihda väriä
);
}
@@ -728,7 +729,7 @@ export default function App() {
- Clicks on the page: {clicks}
+ Klikkauksia sivulla: {clicks}
);
}
diff --git a/src/content/learn/scaling-up-with-reducer-and-context.md b/src/content/learn/scaling-up-with-reducer-and-context.md
index 0281afcec..c57cb55dc 100644
--- a/src/content/learn/scaling-up-with-reducer-and-context.md
+++ b/src/content/learn/scaling-up-with-reducer-and-context.md
@@ -1,24 +1,24 @@
---
-title: Scaling Up with Reducer and Context
+title: Ylösskaalaus reduktorin ja kontekstin avulla
---
-Reducers let you consolidate a component's state update logic. Context lets you pass information deep down to other components. You can combine reducers and context together to manage state of a complex screen.
+Reduktorien avulla voit yhdistää komponentin tilan päivityslogiikan. Kontekstin avulla voit välittää tietoa syvälle muihin komponentteihin. Voit yhdistää reduktoreita ja konteksteja hallitaksesi monimutkaisen ruudun tilaa.
-* How to combine a reducer with context
-* How to avoid passing state and dispatch through props
-* How to keep context and state logic in a separate file
+* Miten yhdistää reduktori ja konteksti
+* Miten välttää tilan ja toimintojen välittäminen propsien kautta
+* Miten pitää konteksti ja tilalogiikka erillisessä tiedostossa
-## Combining a reducer with context {/*combining-a-reducer-with-context*/}
+## Reduktorin yhdistäminen kontekstin kanssa {/*combining-a-reducer-with-context*/}
-In this example from [the introduction to reducers](/learn/extracting-state-logic-into-a-reducer), the state is managed by a reducer. The reducer function contains all of the state update logic and is declared at the bottom of this file:
+Tässä esimerkissä [reduktoriin tutustumisesta](/learn/extracting-state-logic-into-a-reducer), tilaa hallitaan reduktorilla. Reduktorifunktio sisältää kaiken tilan päivityslogiikan ja se on määritelty tiedoston loppuun:
@@ -207,9 +207,9 @@ ul, li { margin: 0; padding: 0; }
-A reducer helps keep the event handlers short and concise. However, as your app grows, you might run into another difficulty. **Currently, the `tasks` state and the `dispatch` function are only available in the top-level `TaskApp` component.** To let other components read the list of tasks or change it, you have to explicitly [pass down](/learn/passing-props-to-a-component) the current state and the event handlers that change it as props.
+Reduktori helpottaa pitämään tapahtumakäsittelijät lyhyinä ja tiiviinä. Kuitenkin, kun sovelluksesi kasvaa, saataat törmätä toiseen haasteeseen. **Tällä hetkellä, `tasks` tila ja `dispatch` funktio ovat vain saatavilla ylätason `TaskApp` komponentissa.** Jotta muut komponentit voisivat lukea tehtävälistan tai muuttaa sitä, sinun on erikseen [välitettävä](/learn/passing-props-to-a-component) nykyinen tila ja tapahtumakäsittelijät, jotka muuttavat sitä propsien kautta.
-For example, `TaskApp` passes a list of tasks and the event handlers to `TaskList`:
+Esimerkiksi, `TaskApp` välittää tehtävälistan ja tapahtumakäsittelijät `TaskList` komponentille:
```js
```
-In a small example like this, this works well, but if you have tens or hundreds of components in the middle, passing down all state and functions can be quite frustrating!
+Pienessä esimerkissä kuten tässä, tämä toimii hyvin, mutta jos sinulla on kymmeniä tai satoja komponentteja välissä, tilan ja funktioiden välittäminen voi olla melko ärsyttävää!
-This is why, as an alternative to passing them through props, you might want to put both the `tasks` state and the `dispatch` function [into context.](/learn/passing-data-deeply-with-context) **This way, any component below `TaskApp` in the tree can read the tasks and dispatch actions without the repetitive "prop drilling".**
+Tämän takia vaihtoehtoinen tapa on laittaa sekä `tasks` tila että `dispatch` funktio [kontekstiin](/learn/passing-data-deeply-with-context). **Tällöin, minkä tahansa komponentin alla oleva komponentti voi lukea tehtävälistan ja kutsua tapahtumakäsittelijöitä ilman toistuvaa "prop drillingia".**
-Here is how you can combine a reducer with context:
+Tässä on tapa yhdistää reduktori kontekstiin:
-1. **Create** the context.
-2. **Put** state and dispatch into context.
-3. **Use** context anywhere in the tree.
+1. **Luo** konteksti.
+2. **Aseta** tila ja dispatch -funktio kontekstiin.
+3. **Käytä** kontekstia missä tahansa puun sijainnissa.
-### Step 1: Create the context {/*step-1-create-the-context*/}
+### 1. Vaihe: Luo konteksti {/*step-1-create-the-context*/}
-The `useReducer` Hook returns the current `tasks` and the `dispatch` function that lets you update them:
+`useReducer` hookki palauttaa nykyisen `tasks` tilan ja `dispatch` funktion, joka mahdollistaa sen päivittämisen:
```js
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
```
-To pass them down the tree, you will [create](/learn/passing-data-deeply-with-context#step-2-use-the-context) two separate contexts:
+Välittääksesi ne puun alle, sinun täytyy [luoda](/learn/passing-data-deeply-with-context#step-2-use-the-context) kaksi erillistä kontekstia:
-- `TasksContext` provides the current list of tasks.
-- `TasksDispatchContext` provides the function that lets components dispatch actions.
+- `TasksContext` tarjoaa nykyisen listan tehtävistä.
+- `TasksDispatchContext` tarjoaa funktion, jonka avulla voit lähettää toimintoja.
-Export them from a separate file so that you can later import them from other files:
+Exporttaa ne erillisestä tiedostosta, jotta voit myöhemmin importata ne muista tiedostoista:
@@ -448,11 +448,11 @@ ul, li { margin: 0; padding: 0; }
-Here, you're passing `null` as the default value to both contexts. The actual values will be provided by the `TaskApp` component.
+Tässä, välität `null`:n oleetusarvona molemmille konteksteille. Todelliset arvot tarjotaan `TaskApp` komponentissa.
-### Step 2: Put state and dispatch into context {/*step-2-put-state-and-dispatch-into-context*/}
+### 2. Vaihe: Aseta tila ja dispatch kontekstiin {/*step-2-put-state-and-dispatch-into-context*/}
-Now you can import both contexts in your `TaskApp` component. Take the `tasks` and `dispatch` returned by `useReducer()` and [provide them](/learn/passing-data-deeply-with-context#step-3-provide-the-context) to the entire tree below:
+Nyt voit importata molemmat kontekstit `TaskApp` komponentissa. Ota `useReducer()` funktion palauttamat `tasks` ja `dispatch` ja [tarjoa ne](/learn/passing-data-deeply-with-context#step-3-provide-the-context) kaikille komponenteille jotka ovat `TaskApp` komponentin alapuolella:
```js {4,7-8}
import { TasksContext, TasksDispatchContext } from './TasksContext.js';
@@ -470,7 +470,7 @@ export default function TaskApp() {
}
```
-For now, you pass the information both via props and in context:
+Tällä hetkellä välität tiedon sekä propsien että kontekstin kautta:
@@ -669,11 +669,11 @@ ul, li { margin: 0; padding: 0; }
-In the next step, you will remove prop passing.
+Seuraavassa vaiheessa, tulet poistamaan propsien välittämisen.
-### Step 3: Use context anywhere in the tree {/*step-3-use-context-anywhere-in-the-tree*/}
+### 3. Vaihe: Käytä kontekstia missä tahansa sijainnissa puuta {/*step-3-use-context-anywhere-in-the-tree*/}
-Now you don't need to pass the list of tasks or the event handlers down the tree:
+Nyt sinun ei tarvitse välittää listaa tehtävistä tai tapahtumankäsittelijöistä:
```js {4-5}
@@ -685,7 +685,7 @@ Now you don't need to pass the list of tasks or the event handlers down the tree
```
-Instead, any component that needs the task list can read it from the `TaskContext`:
+Sen sijaan, mikä tahansa komponentti, joka tarvitsee tehtävälistan, voi lukea sen `TaskContext`:sta:
```js {2}
export default function TaskList() {
@@ -693,7 +693,7 @@ export default function TaskList() {
// ...
```
-To update the task list, any component can read the `dispatch` function from context and call it:
+Päivittääksesi listan, mikä tahansa komponentti voi lukea `dispatch` -funktion kontekstista ja kutsua sitä:
```js {3,9-13}
export default function AddTask() {
@@ -713,7 +713,7 @@ export default function AddTask() {
// ...
```
-**The `TaskApp` component does not pass any event handlers down, and the `TaskList` does not pass any event handlers to the `Task` component either.** Each component reads the context that it needs:
+**`TaskApp` komponentin ei tarvitse välittää yhtään tapahtumakäsittelijää, eikä `TaskList` komponentin tarvitse myöskään välittää yhtään tapahtumakäsittelijää `Task` komponentille.** Jokainen komponentti lukee kontekstista sen, mitä se tarvitsee:
@@ -897,11 +897,11 @@ ul, li { margin: 0; padding: 0; }
-**The state still "lives" in the top-level `TaskApp` component, managed with `useReducer`.** But its `tasks` and `dispatch` are now available to every component below in the tree by importing and using these contexts.
+**Tila silti "asuu" ylätason `TaskApp` komponentissa, jota hallinnoidaan `useReducer` hookilla.** Mutta sen `tasks` ja `dispatch` ovat nyt saatavilla jokaiselle komponentille, kun konteksti importataan ja käytetään.
-## Moving all wiring into a single file {/*moving-all-wiring-into-a-single-file*/}
+## Koko virityksen siirtäminen yhteen tiedostoon {/*moving-all-wiring-into-a-single-file*/}
-You don't have to do this, but you could further declutter the components by moving both reducer and context into a single file. Currently, `TasksContext.js` contains only two context declarations:
+Sinun ei tarvitse tehdä tätä, mutta voit vielä siistiä komponentteja siirtämällä sekä reduktorin että kontekstin yhteen tiedostoon. Tällä hetkellä, `TasksContext.js` sisältää vain kaksi kontekstin määrittelyä:
```js
import { createContext } from 'react';
@@ -910,11 +910,11 @@ export const TasksContext = createContext(null);
export const TasksDispatchContext = createContext(null);
```
-This file is about to get crowded! You'll move the reducer into that same file. Then you'll declare a new `TasksProvider` component in the same file. This component will tie all the pieces together:
+Tämä tiedosto tulee olemaan täynnä! Siirrät reduktorin yhden tiedoston sisään. Sitten määrität uuden `TasksProvider` komponentin samaan tiedostoon. Tämä komponentti yhdistää kaikki osat yhteen:
-1. It will manage the state with a reducer.
-2. It will provide both contexts to components below.
-3. It will [take `children` as a prop](/learn/passing-props-to-a-component#passing-jsx-as-children) so you can pass JSX to it.
+1. Se hallitsee tilaa reduktorilla.
+2. Se tarjoaa molemmat kontekstit alla oleville komponenteille.
+3. Se [ottaa `children` propsina](/learn/passing-props-to-a-component#passing-jsx-as-children), jotta voit välittää JSX:ää sille.
```js
export function TasksProvider({ children }) {
@@ -930,7 +930,7 @@ export function TasksProvider({ children }) {
}
```
-**This removes all the complexity and wiring from your `TaskApp` component:**
+**Tämä postaa kaiken komplikaation ja virityksen pois `TaskApp` komponentista:**
@@ -1121,7 +1121,7 @@ ul, li { margin: 0; padding: 0; }
-You can also export functions that _use_ the context from `TasksContext.js`:
+Voit myös exportata funktioita, jotka _käyttävät_ kontekstia `TasksContext.js`:stä:
```js
export function useTasks() {
@@ -1133,14 +1133,14 @@ export function useTasksDispatch() {
}
```
-When a component needs to read context, it can do it through these functions:
+Kun komponentin tarvitsee lukea kontekstia, se voi tehdä sen näiden funktioiden kautta:
```js
const tasks = useTasks();
const dispatch = useTasksDispatch();
```
-This doesn't change the behavior in any way, but it lets you later split these contexts further or add some logic to these functions. **Now all of the context and reducer wiring is in `TasksContext.js`. This keeps the components clean and uncluttered, focused on what they display rather than where they get the data:**
+Tämä ei muuta toiminnallisuutta mitenkään, mutta sen avulla voit myöhemmin erottaa näitä konteksteja enemmän tai lisätä logiikkaa funktioihin. **Nyt kaikki kontekstin ja reduktorin viritys on `TasksContext.js` tiedostossa. Tämä pitää komponentit puhtaina ja selkeinä, keskittyen siihen, mitä ne näyttävät, eikä siihen, mistä ne saavat tiedot:**
@@ -1340,27 +1340,27 @@ ul, li { margin: 0; padding: 0; }
-You can think of `TasksProvider` as a part of the screen that knows how to deal with tasks, `useTasks` as a way to read them, and `useTasksDispatch` as a way to update them from any component below in the tree.
+Voit kuvitella `TasksProvider`-komponentin osaksi ruutua, joka osaa käsitellä tehtäviä, `useTasks`-funktion tapana lukea niitä ja `useTasksDispatch`-funktion tapana päivittää niitä mistä tahansa komponentista.
-Functions like `useTasks` and `useTasksDispatch` are called *[Custom Hooks.](/learn/reusing-logic-with-custom-hooks)* Your function is considered a custom Hook if its name starts with `use`. This lets you use other Hooks, like `useContext`, inside it.
+Funktiot kuten `useTasks` ja `useTaskDispatch` kutsutaan **[mukautetuiksi hookseiksi.](/learn/reusing-logic-with-custom-hooks)** Jos funktiosi nimi alkaa `use`-merkillä, se on hookki. Tämä mahdollistaa muun muassa `useContext`-hookin käytön niiden sisällä.
-As your app grows, you may have many context-reducer pairs like this. This is a powerful way to scale your app and [lift state up](/learn/sharing-state-between-components) without too much work whenever you want to access the data deep in the tree.
+Kun sovelluksesi kasvaa, sinulla voi olla useita context-reducer-paria kuten tämä. Tämä on tehokas tapa skaalata sovellus ja [nostaa tila ylös](/learn/sharing-state-between-components) vähällä työllä, kun haluat lukea dataa syvältä puusta.
-- You can combine reducer with context to let any component read and update state above it.
-- To provide state and the dispatch function to components below:
- 1. Create two contexts (for state and for dispatch functions).
- 2. Provide both contexts from the component that uses the reducer.
- 3. Use either context from components that need to read them.
-- You can further declutter the components by moving all wiring into one file.
- - You can export a component like `TasksProvider` that provides context.
- - You can also export custom Hooks like `useTasks` and `useTasksDispatch` to read it.
-- You can have many context-reducer pairs like this in your app.
+- Voit yhdistää reduktorin ja kontekstin, jotta mikä tahansa komponentti voi lukea ja päivittää ylhäällä olevaa tilaa.
+- Tarjotaksesi tila ja dispatch -funktiot alla oleville komponenteille:
+ 1. Luo kaksi kontekstia (yksi tilalle, toinen dispatch -funktiolle).
+ 2. Tarjoa molemmat kontekstit komponentista joka käyttää reduktoria.
+ 3. Käytä jompaa kumpaa kontekstia komponenteista jotka tarvitsevat niitä.
+- Voit siistiä komponentteja vielä lisää siirtämällä kaiken virityksen yhteen tiedostoon.
+ - Voit exportata komponentin kuten `TasksProvider` joka tarjoaa kontekstin.
+ - Voit myös exportata mukautettuja hookkeja kuten `useTasks` ja `useTasksDispatch`.
+- Sinulla voi olla useita konteksti-reduktori -pareja sovelluksessasi.
diff --git a/src/content/learn/sharing-state-between-components.md b/src/content/learn/sharing-state-between-components.md
index 149164fe1..072c2ea1b 100644
--- a/src/content/learn/sharing-state-between-components.md
+++ b/src/content/learn/sharing-state-between-components.md
@@ -1,31 +1,31 @@
---
-title: Sharing State Between Components
+title: Tilan jakaminen komponenttien välillä
---
-Sometimes, you want the state of two components to always change together. To do it, remove state from both of them, move it to their closest common parent, and then pass it down to them via props. This is known as *lifting state up,* and it's one of the most common things you will do writing React code.
+Joskus haluat kahden komponentin tilan muuttuvan yhdessä. Tehdäksesi tämän, poista tila molemmista komponenteista ja siirrä se niiden lähimpään pääkomponenttiin ja välitä se komponenteille propsien kautta. Tätä kutsutaan *tilan nostamiseksi ylös*, ja se on yksi yleinen tapa jota tulet tekemään Reactia kirjoittaessasi.
-- How to share state between components by lifting it up
-- What are controlled and uncontrolled components
+- Miten jakaa tilaa komponenttien välillä "nostamalla ne ylös"
+- Mitä ovat hallitut ja hallitsemattomat komponentit
-## Lifting state up by example {/*lifting-state-up-by-example*/}
+## Esimerkkinä tilan nostaminen {/*lifting-state-up-by-example*/}
-In this example, a parent `Accordion` component renders two separate `Panel`s:
+Tässä esimerkissä, `Accordion` pääkomponentti renderöi kaksi erillistä `Panel` -komponenttia:
* `Accordion`
- `Panel`
- `Panel`
-Each `Panel` component has a boolean `isActive` state that determines whether its content is visible.
+Kullakin `Panel` komponentilla on totuusarvo tyyppinen `isActive` tila, joka päättää onko sen sisältö näkyvissä.
-Press the Show button for both panels:
+Paina Näytä -painiketta molemmista paneeleista:
@@ -41,7 +41,7 @@ function Panel({ title, children }) {
{children}
) : (
setIsActive(true)}>
- Show
+ Näytä
)}
@@ -73,59 +73,59 @@ h3, p { margin: 5px 0px; }
-Notice how pressing one panel's button does not affect the other panel--they are independent.
+Huomaa miten yhden paneelin painikkeen painaminen ei vaikuta toiseen paneeliin--ne ovat toisistaan riippumattomia.
-
+
-Initially, each `Panel`'s `isActive` state is `false`, so they both appear collapsed
+Aluksi, kunkin `Panel` komponentin `isActive` tila on `false`, joten molemmat ovat suljettuina.
-
+
-Clicking either `Panel`'s button will only update that `Panel`'s `isActive` state alone
+Kummankin `Panel` komponentin painikkeen painaminen päivittää vain sen `Panel` komponentin `isActive` tilan yksinään.
-**But now let's say you want to change it so that only one panel is expanded at any given time.** With that design, expanding the second panel should collapse the first one. How would you do that?
+**Muutta sanotaa, että haluat muuttaa sen niin, että vain yksi paneeli voi olla avattuna kerrallaan.** Tällä suunnitelmalla, toisen paneelin avaamisen tulisi sulkea ensimmäinen paneeli. Miten toteuttaisit tämän?
-To coordinate these two panels, you need to "lift their state up" to a parent component in three steps:
+Koordinoidaksesi nämä kaksi paneelia, sinun täytyy "nostaa tila ylös" pääkomponenttiin kolmessa eri vaiheessa:
-1. **Remove** state from the child components.
-2. **Pass** hardcoded data from the common parent.
-3. **Add** state to the common parent and pass it down together with the event handlers.
+1. **Poista** tila lapsikomponentista.
+2. **Välitä** kovakoodattu data yhteisestä pääkomponentista.
+3. **Lisää** tila yhteiseen pääkomponenttiin ja välitä se alas tapahtumakäsittelijöiden kanssa.
-This will allow the `Accordion` component to coordinate both `Panel`s and only expand one at a time.
+Tämä antaa `Accordion` komponentin koordinoida molemmat `Panel` komponentit ja pitää vain yhtä auki kerrallaan.
-### Step 1: Remove state from the child components {/*step-1-remove-state-from-the-child-components*/}
+### 1. Vaihe: Poista tila lapsikomponenteista {/*step-1-remove-state-from-the-child-components*/}
-You will give control of the `Panel`'s `isActive` to its parent component. This means that the parent component will pass `isActive` to `Panel` as a prop instead. Start by **removing this line** from the `Panel` component:
+Luovutat `Panel` komponentin `isActive` ohjauksen sen pääkomponentille. Tämä tarkoittaa, että pääkomponentti välittää `isActive`:n `Panel` komponentille propsien kautta. Aloita **poistamalla tämä rivi** `Panel` komponentista:
```js
const [isActive, setIsActive] = useState(false);
```
-And instead, add `isActive` to the `Panel`'s list of props:
+Ja sen sijaan lisää `isActive` `Panel` komponentin propsilistaan:
```js
function Panel({ title, children, isActive }) {
```
-Now the `Panel`'s parent component can *control* `isActive` by [passing it down as a prop.](/learn/passing-props-to-a-component) Conversely, the `Panel` component now has *no control* over the value of `isActive`--it's now up to the parent component!
+Nyt `Panel` komponentin pääkomponentti *ohjaa* `isActive`:a [välittämällä sen alas propsina.](/learn/passing-props-to-a-component) Lisäksi `Panel` komponentilla *ei ole määräysvaltaa* `isActive` tilan arvoon--se on täysin pääkomponentin vastuulla.
-### Step 2: Pass hardcoded data from the common parent {/*step-2-pass-hardcoded-data-from-the-common-parent*/}
+### 2. Vaihe: Välitä kovakoodattu data yhteisestä pääkomponentista {/*step-2-pass-hardcoded-data-from-the-common-parent*/}
-To lift state up, you must locate the closest common parent component of *both* of the child components that you want to coordinate:
+Tilan nostamiseksi ylös, sinun täytyy etsiä molempien komponenttien lähin jaettu pääkomponetti:
-* `Accordion` *(closest common parent)*
+* `Accordion` *(lähin yhteinen komponentti)*
- `Panel`
- `Panel`
-In this example, it's the `Accordion` component. Since it's above both panels and can control their props, it will become the "source of truth" for which panel is currently active. Make the `Accordion` component pass a hardcoded value of `isActive` (for example, `true`) to both panels:
+Tässä esimerkissä se on `Accordion` komponentti. Sillä se sijaitsee molmepien paneelien yläpuolella ja se voi ohjata niiden propseja, siitä tulee "totuuden lähde" sille kumpi paneeli on aktiivinen. Välitä `Accrdion` komponentista kovakoodattu `isActive` (esimerkiksi, `true`) molemmille paneeleille:
@@ -172,21 +172,21 @@ h3, p { margin: 5px 0px; }
-Try editing the hardcoded `isActive` values in the `Accordion` component and see the result on the screen.
+Kokeile muokata kovakoodattua `isActive` arvoa `Accordion` komponentissa ja katso mitä ruudulla tapahtuu.
-### Step 3: Add state to the common parent {/*step-3-add-state-to-the-common-parent*/}
+### 3. Vaihe: Lisää tila yhteiseen pääkomponenttiin {/*step-3-add-state-to-the-common-parent*/}
-Lifting state up often changes the nature of what you're storing as state.
+Tilan nostaminen ylös usein muuttaa sen luonnetta, mitä tallennat tilana.
-In this case, only one panel should be active at a time. This means that the `Accordion` common parent component needs to keep track of *which* panel is the active one. Instead of a `boolean` value, it could use a number as the index of the active `Panel` for the state variable:
+Tässä tapauksessa vain yhden paneelin tulisi olla aktiivinen kerralla. Tämä tarkoittaa, että yhteisen `Accordion` pääkomponentin tulisi pitää kirjaa siitä, *mikä* paneeli on aktiivinen. `boolean` arvon sijaan, se voisi olla numero, joka vastaa aktiivisen `Panel` komponentin indeksiä:
```js
const [activeIndex, setActiveIndex] = useState(0);
```
+Kun `activeIndex` on `0`, ensimmäinen paneeli on aktiivinen. Kun `activeIndex` on `1`, toinen paneeli on aktiivinen.
-When the `activeIndex` is `0`, the first panel is active, and when it's `1`, it's the second one.
-Clicking the "Show" button in either `Panel` needs to change the active index in `Accordion`. A `Panel` can't set the `activeIndex` state directly because it's defined inside the `Accordion`. The `Accordion` component needs to *explicitly allow* the `Panel` component to change its state by [passing an event handler down as a prop](/learn/responding-to-events#passing-event-handlers-as-props):
+"Show" painikkeen painaminen kummassakin `Panel` komponentissa tulisi muuttaa aktiivista indeksiä `Accordion` komponentissa. `Panel` ei voi asettaa `activeIndex` tilaa suoraan, sillä se on määritelty `Accordion` komponentissa. `Accordion` komponentin täytyy *eksplisiittisesti sallia* `Panel` komponentin muuttaa `activeIndex` tilaa [välittämällä tapahtumakäsittelijä propsina](/learn/responding-to-events#passing-event-handlers-as-props):
```js
<>
@@ -205,7 +205,7 @@ Clicking the "Show" button in either `Panel` needs to change the active index in
>
```
-The `` inside the `Panel` will now use the `onShow` prop as its click event handler:
+`Panel` komponentin sisällä oleva `` käyttää nyt `onShow` propsia sen tapahtumakäsittelijänä:
@@ -266,19 +266,19 @@ h3, p { margin: 5px 0px; }
-This completes lifting state up! Moving state into the common parent component allowed you to coordinate the two panels. Using the active index instead of two "is shown" flags ensured that only one panel is active at a given time. And passing down the event handler to the child allowed the child to change the parent's state.
+Tämä viimeistelee tilan nostamisen ylös! Tilan siirtäminen yhteiseen pääkomponenttiin mahdollistaa kahden paneelin koordinoimisen. Aktiivisen indeksin käyttäminen kahden "onko näkyvissä" muutujan sijaan varmistaa, että vain yksi paneeli on aina aktiivinen. Tapahtumakäsittelijän välittäminen alakomponentille mahdollistaa sen, että alakomponentti voi muuttaa pääkomponentin tilaa.
-
+
-Initially, `Accordion`'s `activeIndex` is `0`, so the first `Panel` receives `isActive = true`
+Aluksi, `Accordion` komponentin `activeIndex` on `0`, joten ensimmäinen `Panel` komponentti vastaanottaa `isActive = true`
-
+
-When `Accordion`'s `activeIndex` state changes to `1`, the second `Panel` receives `isActive = true` instead
+Kun `Accordion` komponentin `activeIndex` tila muuttuu arvoksi `1`, toinen `Panel` komponentti sen sijaan vastaanottaa `isActive = true`
@@ -286,48 +286,48 @@ When `Accordion`'s `activeIndex` state changes to `1`, the second `Panel` receiv
-#### Controlled and uncontrolled components {/*controlled-and-uncontrolled-components*/}
+#### Hallitut ja hallitsemattomat komponentit {/*controlled-and-uncontrolled-components*/}
-It is common to call a component with some local state "uncontrolled". For example, the original `Panel` component with an `isActive` state variable is uncontrolled because its parent cannot influence whether the panel is active or not.
+On yleistä kutsua komponenttia, jotka sisältävät paikallista tilaa, "hallitsemattomiksi". Esimerkiksi, alkuperäinen `Panel` komponentti, joka sisälsi `isActive` tilamuuttujan on hallitsematon, koska sen pääkomponentti ei voi vaikuttaa onko paneeli avoin vai suljettu.
-In contrast, you might say a component is "controlled" when the important information in it is driven by props rather than its own local state. This lets the parent component fully specify its behavior. The final `Panel` component with the `isActive` prop is controlled by the `Accordion` component.
+Vastaavasti voidaan sanoa, että komponentti on "ohjattu" kun sen tärkeät tiedot on ohjattavissa propsien kautta komponentin oman tilan sijaan. Tämä antaa pääkomponentin määritellä täysin sen käyttäytymisen. Viimeisin `Panel` komponentti `isActive` propsilla on `Accordion` komponentin ohjaama.
-Uncontrolled components are easier to use within their parents because they require less configuration. But they're less flexible when you want to coordinate them together. Controlled components are maximally flexible, but they require the parent components to fully configure them with props.
+Hallitsemattomat komponentit ovat helpompia käyttää niiden pääkomponenteissa, sillä ne vaativat vähemmän määrittelyä. Ne eivät kuitenkaan ole yhtä joustavia kun haluat koordinoida niitä yhdessä. Hallitut komponentit ovat mahdollisimman joustavia, mutta vaativat pääkomponentin määrittelemään ne täysin propsien kautta.
-In practice, "controlled" and "uncontrolled" aren't strict technical terms--each component usually has some mix of both local state and props. However, this is a useful way to talk about how components are designed and what capabilities they offer.
+Käytännössä, "hallitut" ja "hallitsemattomat" eivät ole tarkkoja teknisiä termejä--kullakin komponentilla on sekoitus paikallista tilaa ja propseja. Kuitenkin, tämä on hyödyllinen tapa keskutella siitä miten komponentit ovat suunniteltu ja mitä toimintoja ne tarjoavat.
-When writing a component, consider which information in it should be controlled (via props), and which information should be uncontrolled (via state). But you can always change your mind and refactor later.
+Kun kirjoitat komponenttia, harkitse mitä tietoa tulisi ohjata propsien kautta, ja minkä tiedon tulisi olla komponentin paikallista tilaa. Mutta voit kuitenkin aina muuttaa mieltäsi ja muuttaa komponenttia myöhemmin.
-## A single source of truth for each state {/*a-single-source-of-truth-for-each-state*/}
+## Yksi totuuden lähde jokaiselle tilalle {/*a-single-source-of-truth-for-each-state*/}
-In a React application, many components will have their own state. Some state may "live" close to the leaf components (components at the bottom of the tree) like inputs. Other state may "live" closer to the top of the app. For example, even client-side routing libraries are usually implemented by storing the current route in the React state, and passing it down by props!
+React sovelluksessa, monilla komponenteilla on niiden oma tila. Jotkin tilat saattavat "asua" lähempänä lehtikomponentteja (komponetit puun alaosassa) kuten syöttökentissä. Toiset tilat saattavat "asua" lähempänä sovelluksen juurta. Esimerkiksi, selain-puolen reitityskirjastot ovat usein toteuttettu tallentamalla senhetkinen polku Reactin tilaan ja sen välittäminen alas propseilla!
-**For each unique piece of state, you will choose the component that "owns" it.** This principle is also known as having a ["single source of truth".](https://en.wikipedia.org/wiki/Single_source_of_truth) It doesn't mean that all state lives in one place--but that for _each_ piece of state, there is a _specific_ component that holds that piece of information. Instead of duplicating shared state between components, *lift it up* to their common shared parent, and *pass it down* to the children that need it.
+**Kullekin uniikille tilan palaselle valitset komponentin, joka "omistaa" sen.** Tätä käytäntöä kutsutaan ["yhdeksi totuuden lähteeksi".](https://en.wikipedia.org/wiki/Single_source_of_truth) Se ei tarkoita, että kaikki tilat ovat samassa paikassa--vaan, että _jokaiselle_ tilan palaselle on _tietty_ komponentti, joka pitää tiedon yllä. Sen sijaan, että monistaisit jaetun tilan komponenttien välillä, *nostat tilan ylös* niiden lähimpään jaettuun pääkomponenttiin, ja *välität sen alas* alakomponeteille, jotka sitä tarvitsevat.
-Your app will change as you work on it. It is common that you will move state down or back up while you're still figuring out where each piece of the state "lives". This is all part of the process!
+Sovelluksesi muuttuu kun työstät sitä. On yleistä, että siirrät tilaa alas tai takaisin ylös kun vielä mietit missä yksittäiset tilan palaset "asuvat". Tämä on sa prosessia!
-To see what this feels like in practice with a few more components, read [Thinking in React.](/learn/thinking-in-react)
+Nähdäksesi mitä tämä tarkoittaa käytännössä muutamin komponentein, lue [Ajattelu Reactissa.](/learn/thinking-in-react)
-* When you want to coordinate two components, move their state to their common parent.
-* Then pass the information down through props from their common parent.
-* Finally, pass the event handlers down so that the children can change the parent's state.
-* It's useful to consider components as "controlled" (driven by props) or "uncontrolled" (driven by state).
+* Kun haluat koordinoida kahta komponenttia, siirrä niiden tila yhteiseen pääkomponenttiin.
+* Välitä sitten tieto pääkomponentista propseilla.
+* Lopuksi, välitä tapahtumakäsittelijät alas, jotta alakomponentit voivat muuttaa pääkomponentin tilaa.
+* On hyödyllistä ajatella komponentteja "hallittuina" (ohjataan propseilla) tai "hallitsemattomina" (ohjataan tilalla).
-#### Synced inputs {/*synced-inputs*/}
+#### Synkronoidut tulot {/*synced-inputs*/}
-These two inputs are independent. Make them stay in sync: editing one input should update the other input with the same text, and vice versa.
+Nämä kaksi syöttökenttää ovat toisistaan riippumattomia. Tee niistä synkronoituja: yhden muuttaminen päivittää toisen samalla tekstillä ja päin vastoin.
-You'll need to lift their state up into the parent component.
+Sinun täytyy nostaa niiden tila ylös yhteiseen pääkomponenttiin.
@@ -374,7 +374,7 @@ label { display: block; }
-Move the `text` state variable into the parent component along with the `handleChange` handler. Then pass them down as props to both of the `Input` components. This will keep them in sync.
+Siirrä `text` tilamuuttuja ylös yhteiseen pääkomponenttiin `handleChange` tapahtumakäsittelijän kanssa. Sitten välitä ne alas propseina molemmille `Input` komponenteille. Tämä pitää ne synkronoituna.
@@ -427,17 +427,17 @@ label { display: block; }
-#### Filtering a list {/*filtering-a-list*/}
+#### Listan suodattaminen {/*filtering-a-list*/}
-In this example, the `SearchBar` has its own `query` state that controls the text input. Its parent `FilterableList` component displays a `List` of items, but it doesn't take the search query into account.
+Tässä esimerkissä `SearchBar`:lla on sen oma `query` tila, joka ohjaa syöttökenttää. Sen `FilterableList` pääkomponentti näyttää `List`:an kohteita, mutta se ei huomioi hakulauseketta.
-Use the `filterItems(foods, query)` function to filter the list according to the search query. To test your changes, verify that typing "s" into the input filters down the list to "Sushi", "Shish kebab", and "Dim sum".
+Käytä `filterItems(foods, query)` funktiota listan suodattamiseksi hakulausekkeen perusteella. Testataksesi muutokset, varmista, että "s":n kirjoittaminen kenttään suodattaa listan kohteisiin "Sushi", "Shish kebab" ja "Dim sum".
-Note that `filterItems` is already implemented and imported so you don't need to write it yourself!
+Huomaa, että `filterItems` on jo toteutettu ja importattu, joten sinun ei tarvitse kirjoittaa sitä itse!
-You will want to remove the `query` state and the `handleChange` handler from the `SearchBar`, and move them to the `FilterableList`. Then pass them down to `SearchBar` as `query` and `onChange` props.
+Sinun täytyy poistaa `query` tila ja `handleChange` tapahtumakäsittelijä `SearchBar` komponentista ja siirtää ne ylös `FilterableList` pääkomponenttiin. Sitten välitä ne alas `SearchBar` komponentille `query` ja `onChange` propseina.
diff --git a/src/content/learn/state-a-components-memory.md b/src/content/learn/state-a-components-memory.md
index 1dbaab4a9..c0f828cb9 100644
--- a/src/content/learn/state-a-components-memory.md
+++ b/src/content/learn/state-a-components-memory.md
@@ -1,5 +1,5 @@
---
-title: "State: A Component's Memory"
+title: "Tila: Komponentin muisti"
---
@@ -10,16 +10,16 @@ Components often need to change what's on the screen as a result of an interacti
-* How to add a state variable with the [`useState`](/reference/react/useState) Hook
-* What pair of values the `useState` Hook returns
-* How to add more than one state variable
-* Why state is called local
+* Miten lisätä tilamuuttuja [`useState`](/reference/react/useState) hookilla
+* Minkä arvoparin `useState` hookki palauttaa
+* Miten lisätä useampi tilamuuttuja
+* Miksi tilaa sanotaan paikalliseksi
-## When a regular variable isn’t enough {/*when-a-regular-variable-isnt-enough*/}
+## Kun tavallinen muuttuja ei riitä {/*when-a-regular-variable-isnt-enough*/}
-Here's a component that renders a sculpture image. Clicking the "Next" button should show the next sculpture by changing the `index` to `1`, then `2`, and so on. However, this **won't work** (you can try it!):
+Tässä on komponentti, joka renderöi kuvan veistoksesta. Klikkaamalla "Next" painiketta pitäisi seuraavan veistoksen näkyä, muuttamalla `index` lukua `1`:een, `2`:een ja niin edelleen. Kuitenkaan tämä **ei toimi** (voit kokeilla!):
@@ -151,46 +151,46 @@ button {
-The `handleClick` event handler is updating a local variable, `index`. But two things prevent that change from being visible:
+`handleClick()` tapahtumakäsittelijä päivittää paikallista `index` muuttujaa. Kaksi asiaa kuitenkin estävät muutoksen näkymisen:
-1. **Local variables don't persist between renders.** When React renders this component a second time, it renders it from scratch—it doesn't consider any changes to the local variables.
-2. **Changes to local variables won't trigger renders.** React doesn't realize it needs to render the component again with the new data.
+1. **Paikalliset muuttujat eivät pysy voimassa renderien välillä.** Kun React renderöi tämän komponentin toiseen kertaan, se luo sen alusta. Se ei ota huomioon paikallisten muuttujien muutoksia.
+2. **Muutokset paikallisiin muuttujiin eivät käynnistä uutta renderöintiä.** React ei huomaa, että sen täytyy renderöidä komponentti uudelleen uusien tietojen kanssa.
-To update a component with new data, two things need to happen:
+Päivittääksesi komponentti uudella datalla, kaksi asiaa täytyy tapahtua:
-1. **Retain** the data between renders.
-2. **Trigger** React to render the component with new data (re-rendering).
+1. **Säilyttää** data renderien välillä.
+2. **Käynnistää** React renderöimään komponenttin uudella datalla (uudelleenrenderöinti).
-The [`useState`](/reference/react/useState) Hook provides those two things:
+[`useState`](/reference/react/useState) hookki tarjoaa molemmat näistä:
-1. A **state variable** to retain the data between renders.
-2. A **state setter function** to update the variable and trigger React to render the component again.
+1. **Tilamuuttujan** ylläpitämään data renderien välillä.
+2. **Tilan asettajafunktio** päivittämään muuttujaa ja käynnistämään komponentin uudelleenrenderöinti.
-## Adding a state variable {/*adding-a-state-variable*/}
+## Tilamuuttujan lisääminen {/*adding-a-state-variable*/}
-To add a state variable, import `useState` from React at the top of the file:
+Lisätäksesi tilamuuttuja, importtaa `useState` Reactista tiedoston alussa:
```js
import { useState } from 'react';
```
-Then, replace this line:
+Sitten, korvaa tämä rivi:
```js
let index = 0;
```
-with
+tällä
```js
const [index, setIndex] = useState(0);
```
-`index` is a state variable and `setIndex` is the setter function.
+`index` on tilamuuttuja ja `setIndex` on tilan asettajafunktio.
-> The `[` and `]` syntax here is called [array destructuring](https://javascript.info/destructuring-assignment) and it lets you read values from an array. The array returned by `useState` always has exactly two items.
+> Aaltosulkeilla `[` ja `]` oleva syntaksi on nimeltään [array destructuring](https://javascript.info/destructuring-assignment) ja sen avulla voit lukea arvoja listasta. `useState` palauttaa aina listan, jossa on kaksi kohdetta.
-This is how they work together in `handleClick`:
+Tässä miten ne toimii yhdessä `handleClick()` funktiossa:
```js
function handleClick() {
@@ -198,7 +198,7 @@ function handleClick() {
}
```
-Now clicking the "Next" button switches the current sculpture:
+Nyt klikkaamalla "Next" painiketta, kuva veistoksesta vaihtuu:
@@ -331,57 +331,57 @@ button {
-### Meet your first Hook {/*meet-your-first-hook*/}
+### Tapaa ensimmäinen hookkisi {/*meet-your-first-hook*/}
-In React, `useState`, as well as any other function starting with "`use`", is called a Hook.
+Reactissa `useState`, kuten muutkin funktiot jotka alkavat sanalla "`use`", ovat hookkeja.
-*Hooks* are special functions that are only available while React is [rendering](/learn/render-and-commit#step-1-trigger-a-render) (which we'll get into in more detail on the next page). They let you "hook into" different React features.
+*Hookit* ovat erityisiä funktioita, jotka ovat saatavilla vain kun React [renderöi](/learn/render-and-commit#step-1-trigger-a-render) (aihe, johon perehdymme enemmän seuraavalla sivulla page). Näillä voit "koukata" erilaisiin Reactin toimintoihin.
-State is just one of those features, but you will meet the other Hooks later.
+Tila on vain yksi näistä toiminnoista, mutta tulet tapaamaan toiset hookit myöhemmin.
-**Hooks—functions starting with `use`—can only be called at the top level of your components or [your own Hooks.](/learn/reusing-logic-with-custom-hooks)** You can't call Hooks inside conditions, loops, or other nested functions. Hooks are functions, but it's helpful to think of them as unconditional declarations about your component's needs. You "use" React features at the top of your component similar to how you "import" modules at the top of your file.
+**Hookit, eli `use`-sanalla alkavat funktiot, ovat kutsuttavissa ainoastaan komponenttisi ylätasossa tai [omista hookeistasi.](/learn/reusing-logic-with-custom-hooks)** Et voi kutsua hookkeja ehtojen, silmukoiden tai muiden sisennettyjen funktioiden sisällä. Hookit ovat funktioita, mutta on hyödyllistä ajatella niitä kuin ehdottomina määräyksinä komponenttisi tarpeista. Sinä käytät ("use") Reactin ominaisuuksia komponentin yläosassa samalla tavalla kuin "importtaat" moduuleja tiedoston yläosassa.
-### Anatomy of `useState` {/*anatomy-of-usestate*/}
+### `useState`:n anatomia {/*anatomy-of-usestate*/}
-When you call [`useState`](/reference/react/useState), you are telling React that you want this component to remember something:
+Kun kutsut [`useState`](/reference/react/useState):a, sanot Reactille, että haluat tämän komponentin muistavan jotain:
```js
const [index, setIndex] = useState(0);
```
-In this case, you want React to remember `index`.
+Tässä tapauksessa haluat Reactin muistavan `index`:n.
-The convention is to name this pair like `const [something, setSomething]`. You could name it anything you like, but conventions make things easier to understand across projects.
+Yleinen tapa on nimetä tämä pari kuten `const [jotain, setJotain]`. Voit nimetä sen miten haluat, mutta yleisien tapojen avulla koodia on helpompi ymmärtää projektien välillä.
-The only argument to `useState` is the **initial value** of your state variable. In this example, the `index`'s initial value is set to `0` with `useState(0)`.
+Ainoa argumentti `useState`:lle on tilamuuttujan **aloitusarvo**. Tässä esimerkissä `index`:n aloitusarvo on `0` kun käytimme `useState(0)`.
-Every time your component renders, `useState` gives you an array containing two values:
+Joka kerta kun komponenttisi renderöityy, `useState` palauttaa listan sisältäen kaksi kohdetta:
-1. The **state variable** (`index`) with the value you stored.
-2. The **state setter function** (`setIndex`) which can update the state variable and trigger React to render the component again.
+1. **Tilamuuttujan** (`index`) missä on arvo, jonka tallensit.
+2. **Tilan asettajafunktion** (`setIndex`) joka voi piäivittää tilamuuttujaa ja käynnistää komponentin uudelleenrenderöinnin.
-Here's how that happens in action:
+Tässä miten se tapahtuu toiminnassa:
```js
const [index, setIndex] = useState(0);
```
-1. **Your component renders the first time.** Because you passed `0` to `useState` as the initial value for `index`, it will return `[0, setIndex]`. React remembers `0` is the latest state value.
-2. **You update the state.** When a user clicks the button, it calls `setIndex(index + 1)`. `index` is `0`, so it's `setIndex(1)`. This tells React to remember `index` is `1` now and triggers another render.
-3. **Your component's second render.** React still sees `useState(0)`, but because React *remembers* that you set `index` to `1`, it returns `[1, setIndex]` instead.
-4. And so on!
+1. **Your component renders the first time.** Koska välitit arvon `0`, `useState`-arvon `index` alkuarvoksi, se palauttaa arvon `[0, setIndex]`. React muistaa, että `0` on viimeisin tila-arvo.
+2. **Päivität tilan.** Kun käyttäjä klikkaa painiketta, se kutsuu `setIndex(index + 1)`. `index` on `0`, joten se on `setIndex(1)`. Tämä käskee Reactia muistamaan, että `index` on nyt `1` ja käynnistämään toisen renderöinnin.
+3. **Komponenttisi toinen renderöinti.** React näkee silti `useState(0)`, mutta koska React *muistaa*, että asetit `index`:n aroon `1`, se palauttaa `[1, setIndex]` kuitenkin.
+4. Ja niin edelleen!
-## Giving a component multiple state variables {/*giving-a-component-multiple-state-variables*/}
+## Useiden tilamuuttujien antaminen komponentille {/*giving-a-component-multiple-state-variables*/}
-You can have as many state variables of as many types as you like in one component. This component has two state variables, a number `index` and a boolean `showMore` that's toggled when you click "Show details":
+Voit lisätä niin monta tilamuuttujaa niin monessa eri tyypissä kuin haluat komponentin sisälle. Tällä komponentilla on kaksi tilamuuttujaa, `index` numero sekä `showMore` totuusarvo, jota vaihdetaan kun klikkaat "Show details":
@@ -520,19 +520,19 @@ button {
-It is a good idea to have multiple state variables if their state is unrelated, like `index` and `showMore` in this example. But if you find that you often change two state variables together, it might be easier to combine them into one. For example, if you have a form with many fields, it's more convenient to have a single state variable that holds an object than state variable per field. Read [Choosing the State Structure](/learn/choosing-the-state-structure) for more tips.
+Hyvä idea on tehdä useita tilamuuttujia jos ne eivät liity toisiinsa, kuten `index` ja `showMore` tässä esimerkissä. Mutta jos löydät itsesi usein vaihtamassa kahta tilamuuttujaa yhdessä, saattaa olla helpompaa yhdistää ne yhteen. Esimerkiksi, jos sinulla on lomake monilla kentillä, voi olla kätevää pitää tila yhdessä oliossa ennemin kuin yksi tilamuuttuja per kenttä. [Tilarakenteen päättäminen](/learn/choosing-the-state-structure) -sivulla on enemmän vinkkejä tähän.
-#### How does React know which state to return? {/*how-does-react-know-which-state-to-return*/}
+#### Miten React tietää minkä tilan palauttaa? {/*how-does-react-know-which-state-to-return*/}
-You might have noticed that the `useState` call does not receive any information about *which* state variable it refers to. There is no "identifier" that is passed to `useState`, so how does it know which of the state variables to return? Does it rely on some magic like parsing your functions? The answer is no.
+Olet saattanut huomata, että `useState` kutsu ei vastaanota tietoa siitä *mitä* tilamuuttujaa se vastaa. Ei ole mitään "tunnistetta", joka välitettäisiin `useState`:lle, joten miten se tietää minkä tilamuuttujan palauttaa? Nojaako se johonkin taikaan kuten funktioiden parsimiseen? Ei.
-Instead, to enable their concise syntax, Hooks **rely on a stable call order on every render of the same component.** This works well in practice because if you follow the rule above ("only call Hooks at the top level"), Hooks will always be called in the same order. Additionally, a [linter plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) catches most mistakes.
+Sen sijaan, mahdollistaakseen niiden tiiviin syntaksin, hookit **turvautuvat vakaaseen kutsujärjestykseen saman komponentin jokaisella renderöinnillä**. Tämä toimii hyvin käytännössä, koska jos seuraat ylhäällä mainittua sääntöä ("kutsu hookkeja vain ylätasossa"), hookit tullaan kutsumaan aina samassa järjestyksessä. Lisäksi, [lintteri-lisäosa](https://www.npmjs.com/package/eslint-plugin-react-hooks) huomaa suurimman osan virheistä.
-Internally, React holds an array of state pairs for every component. It also maintains the current pair index, which is set to `0` before rendering. Each time you call `useState`, React gives you the next state pair and increments the index. You can read more about this mechanism in [React Hooks: Not Magic, Just Arrays.](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e)
+Sisäisesti, React pitää yllään listan tilamuuttujapareista jokaiselle komponentille. Se pitää yllään myös sen hetkistä indeksiä, joka on asetettu `0`:ksi ennen renderöintiä. Joka kerta kun kutsut `useState`:a, React antaa sinulle seuraavan tilaparin ja kasvattaa indeksiä. Voit lukea lisää tästä mekanismista linkistä: [React Hooks: Not Magic, Just Arrays](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e).
-This example **doesn't use React** but it gives you an idea of how `useState` works internally:
+Tämä esimerkki **ei käytä Reactia**, mutta antaa idean siitä miten `useState` toimii sisäisesti:
@@ -724,15 +724,15 @@ button { display: block; margin-bottom: 10px; }
-You don't have to understand it to use React, but you might find this a helpful mental model.
+Sinun ei tarvitse ymmärtää tätä käyttääksesi Reactia, mutta saatat kokea sen hyödyllisenä.
-## State is isolated and private {/*state-is-isolated-and-private*/}
+## Tila on eristetty ja yksityinen {/*state-is-isolated-and-private*/}
-State is local to a component instance on the screen. In other words, **if you render the same component twice, each copy will have completely isolated state!** Changing one of them will not affect the other.
+Tila on paikallinen kussakin komponentissa. Toisin sanoen, **jos renderöit saman komponentin kahdesti, kummallakin on niiden oma eristetty tila!** Yhden muuttaminen ei vaikuta toiseen.
-In this example, the `Gallery` component from earlier is rendered twice with no changes to its logic. Try clicking the buttons inside each of the galleries. Notice that their state is independent:
+Tässä esimerkissä, aiempi `Gallery` komponetti renderöidään kahdesti ilman muutoksia sen logiikkaan. Kokeile klikata painikkeita kummassakin galleriassa. Huomaat, että niiden tilat ovat itsenäisiä:
@@ -891,21 +891,21 @@ button {
-This is what makes state different from regular variables that you might declare at the top of your module. State is not tied to a particular function call or a place in the code, but it's "local" to the specific place on the screen. You rendered two ` ` components, so their state is stored separately.
+Tämä tekee tilasta erilaisen kuin tavalliset muuttujat, joita saatat määritellä moduulisi yläosassa. Tilaa ei ole yhdistetty tiettyyn funktiokutsuun tai paikkaan koodissa, mutta se on "paikallinen" siinä kohtaa ruutua. Renderöit kaksi ` ` komponenttia, joten niiden tila on tallennettu erillään.
-Also notice how the `Page` component doesn't "know" anything about the `Gallery` state or even whether it has any. Unlike props, **state is fully private to the component declaring it.** The parent component can't change it. This lets you add state to any component or remove it without impacting the rest of the components.
+Huomaa myös kuinka `Page` komponentti ei "tiedä" mitään `Gallery`:n tilasta tai edes onko sillä tilaa. Toisin kuin propsit, **tila on täysin yksityinen komponentille, joka sen määrittelee**. Yläkomponetti ei voi muuttaa sitä. Tämän avulla voit lisätä tilan mihin tahansa komponenttiin tai poistaa sen vaikuttamatta muihin komponentteihin.
-What if you wanted both galleries to keep their states in sync? The right way to do it in React is to *remove* state from child components and add it to their closest shared parent. The next few pages will focus on organizing state of a single component, but we will return to this topic in [Sharing State Between Components.](/learn/sharing-state-between-components)
+Entä jos haluaisit molempien gallerioiden pitäbän niiden tilan synkronisoituna? Oikea tapa tehdä tämä Reactissa on *poistamalla* tila alakomponenteista ja listätä se niiden lähimpään jaettuun yläkomponenttiin. Seuraavat muutamat sivut keskittyvät yhden komponentin tilan järjestämiseen , mutta palaamme tähän aiheeseen [Sharing State Between Components](/learn/sharing-state-between-components) -sivulla.
-* Use a state variable when a component needs to "remember" some information between renders.
-* State variables are declared by calling the `useState` Hook.
-* Hooks are special functions that start with `use`. They let you "hook into" React features like state.
-* Hooks might remind you of imports: they need to be called unconditionally. Calling Hooks, including `useState`, is only valid at the top level of a component or another Hook.
-* The `useState` Hook returns a pair of values: the current state and the function to update it.
-* You can have more than one state variable. Internally, React matches them up by their order.
-* State is private to the component. If you render it in two places, each copy gets its own state.
+* Käytä tilamuuttujaa kun komponentin täytyy "muistaa" jotain tietoa renderien välillä.
+* Tilamuuttujat määritellään kutsumalla `useState` hookkia.
+* Hookit ovat erityisiä funktioita, jotka alkavat sanalla `use`. Niiden avulla voit "koukata" Reactin toimintoihin kuten tilaan.
+* Hookit saattavat muistuttaa sinua importeista: ne pitää kutsua ilman ehtoja. Hookkien kutsuminen, `useState` mukaanlukien, on sallittua vain komponentin yläosassa tai toisessa hookissa.
+* `useState` hookki palauttaa arvoparin: nykyisen tilan ja funktion jolla päivittää sitä.
+* Voit tehdä useita tilamuuttujia. Sisäisesti, React yhdistää ne järjestyksen perusteella.
+* Tila on yksityistä komponentille. Jos renderöit niitä kahdessa paikassa, kukin saa oman tilan.
@@ -913,11 +913,11 @@ What if you wanted both galleries to keep their states in sync? The right way to
-#### Complete the gallery {/*complete-the-gallery*/}
+#### Viimeistele galleria {/*complete-the-gallery*/}
-When you press "Next" on the last sculpture, the code crashes. Fix the logic to prevent the crash. You may do this by adding extra logic to event handler or by disabling the button when the action is not possible.
+Kun painat "Next" painiketta viimesellä veistoksella, koodi kaatuu. Korjaa logiikka joka estää kaatumista. Voit tehdä tämän lisäämällä logiikkaa tapahtumakäsittelijään tai poistamalla painikkeen käytöstä kun toimintoa ei ole mahdollista tehdä.
-After fixing the crash, add a "Previous" button that shows the previous sculpture. It shouldn't crash on the first sculpture.
+Korjaamisen jälkeen, lisää "Previous" painike, joka näyttää edellisen veistoksen. Sen ei tulisi kaatua ensimmäisessä veistoksessa.
@@ -1059,7 +1059,7 @@ img { width: 120px; height: 120px; }
-This adds a guarding condition inside both event handlers and disables the buttons when needed:
+Tämä lisää suojaavan ehdon molempiin tapahtumakäsittelijöihin sekä poistaa painikkeen käytöstä tarvittaessa:
@@ -1219,13 +1219,13 @@ img { width: 120px; height: 120px; }
-Notice how `hasPrev` and `hasNext` are used *both* for the returned JSX and inside the event handlers! This handy pattern works because event handler functions ["close over"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) any variables declared while rendering.
+Huomaa miten `hasPrev` ja `hasNext` ovat käytössä *sekä* palautetussa JSX koodissa että tapahtumakäsittelijöissä! Tämä kätevä tapa toimii koska tapahtumakäsittelijäfunktiot ["sulkevat" (engl. "close over")](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) kaikki määritellyt muuttujat renderöinnin aikana.
-#### Fix stuck form inputs {/*fix-stuck-form-inputs*/}
+#### Korjaa lomakkeen tukkiutuneet syöttökentät {/*fix-stuck-form-inputs*/}
-When you type into the input fields, nothing appears. It's like the input values are "stuck" with empty strings. The `value` of the first ` ` is set to always match the `firstName` variable, and the `value` for the second ` ` is set to always match the `lastName` variable. This is correct. Both inputs have `onChange` event handlers, which try to update the variables based on the latest user input (`e.target.value`). However, the variables don't seem to "remember" their values between re-renders. Fix this by using state variables instead.
+Kun kirjoitat syöttökenttiin, mitään ei tapahdu. Aivan kuin kenttien arvot ovat "jumissa" tyhjillä merkkijonoilla. Ensimmäisen ` ` elementin `value` on asetettu aina vastaamaan `firstName` muuttujaa ja toisen ` ` elementin `value` vastaamaan `lastName` muuttujaa. Tämä on tarkoituksenmukaista. Molemmilla kentillä on `onChange` tapahtumakäsittelijä, joka pyrkii päivittämään muuttujia käyttäjän syötteen (`e.target.value`) perusteella. Kuitenkaan, muuttujat eivät näytä "muistavan" niiden arvoja renderöintien välillä. Korjaa tämä käyttämällä tilamuuttujia tavallisten muuttujien sijaan.
@@ -1274,7 +1274,7 @@ h1 { margin-top: 10px; }
-First, import `useState` from React. Then replace `firstName` and `lastName` with state variables declared by calling `useState`. Finally, replace every `firstName = ...` assignment with `setFirstName(...)`, and do the same for `lastName`. Don't forget to update `handleReset` too so that the reset button works.
+Ensiksi, importtaa `useState` Reactista. Sitten korvaa `firstName` ja `lastName` tilamuuttujilla, jotka määritellään kutsumalla `useState` funktiota. Lopuksi, korvaa jokainen `firstName = ...` määrittely `setFirstName(...)` kutsulla, ja tee sama `lastName`:lle. Älä unohda päivittää `handleReset` funktiota myös, jotta reset painike toimii myöskin.
@@ -1325,13 +1325,13 @@ h1 { margin-top: 10px; }
-#### Fix a crash {/*fix-a-crash*/}
+#### Korjaa kaatuminen {/*fix-a-crash*/}
-Here is a small form that is supposed to let the user leave some feedback. When the feedback is submitted, it's supposed to display a thank-you message. However, it crashes with an error message saying "Rendered fewer hooks than expected". Can you spot the mistake and fix it?
+Tässä on pieni lomake, jonka olisi tarkoitus antaa käyttäjän jättää palautetta. Kun palaute lähetetään, sen olisi tarkoitus näyttää kiitosviesti. Kuitenkin, se kaatuu virheellä "Rendered fewer hooks than expected". Huomaatko virheen ja pystytkö korjaamaan sen?
-Are there any limitations on _where_ Hooks may be called? Does this component break any rules? Check if there are any comments disabling the linter checks--this is where the bugs often hide!
+Onko mitään rajoituksia _missä_ hookkeja voidaan kutsua? Rikkooko tämä komponentti mitään sääntöjä? Tarkista onko kommentteja, jotka estävät litterien tarkistuksen--täällä yleensä bugit usein piiloutuvat!
@@ -1370,9 +1370,9 @@ export default function FeedbackForm() {
-Hooks can only be called at the top level of the component function. Here, the first `isSent` definition follows this rule, but the `message` definition is nested in a condition.
+Hookkeja voidaan kutsua vain komponentin ylätasossa. Tässä, ensimmäinen `isSent` määrittely noudattaa tätä sääntöä, mutta `message` määrittely on tehty ehtolauseen sisällä.
-Move it out of the condition to fix the issue:
+Siirrä se pois ehtolauseesta korjataksesi ongelman:
@@ -1407,9 +1407,9 @@ export default function FeedbackForm() {
-Remember, Hooks must be called unconditionally and always in the same order!
+Muista, hookit täytyy kutsua ilman ehtoja ja aina samassa järjestyksessä!
-You could also remove the unnecessary `else` branch to reduce the nesting. However, it's still important that all calls to Hooks happen *before* the first `return`.
+Voit myös poistaa tarpeettoman `else` haaran sisennyksen vähentämiseksi. Kuitenkin on silti tärkeää, että kaikki kutsut hookkeihin tapahtuvat *ennen* ensimmäistä `return` lausetta.
@@ -1444,19 +1444,19 @@ export default function FeedbackForm() {
-Try moving the second `useState` call after the `if` condition and notice how this breaks it again.
+Kokeile siirtää toinen `useState` kutsu `if` lauseen jälkeen ja huomaat miten tämä hajoaa uudelleen.
-If your linter is [configured for React](/learn/editor-setup#linting), you should see a lint error when you make a mistake like this. If you don't see an error when you try the faulty code locally, you need to set up linting for your project.
+Jos lintterisi on [määritelty Reactille](/learn/editor-setup#linting), pitäisi näkyä lint-virhe kun teet tämänkaltaisen virheen. Jos et näe virhettä kun kokeilet viallista koodia paikallisesti, sinun täytyy määritellä se käännöstyökaluusi.
-#### Remove unnecessary state {/*remove-unnecessary-state*/}
+#### Poista tarpeeton tila {/*remove-unnecessary-state*/}
-When the button is clicked, this example should ask for the user's name and then display an alert greeting them. You tried to use state to keep the name, but for some reason it always shows "Hello, !".
+Kun painiketta painetaan, tämän esimerkin tulisi kysyä käyttäjän nimeä ja sitten tervehtiä ilmoituksella. Yritit tallentaa nimen tilaan, mutta jostain syystä se näyttää "Hello, !".
-To fix this code, remove the unnecessary state variable. (We will discuss about [why this didn't work](/learn/state-as-a-snapshot) later.)
+Korjataksesi tämän koodin, poista tarpeeton tilamuuttuja. (Katsotaan myöhemmin [miksi tämä ei toiminut](/learn/state-as-a-snapshot).)
-Can you explain why this state variable was unnecessary?
+Pystytkö selittämään miksi tilamuuttuja on tarpeeton?
@@ -1483,7 +1483,7 @@ export default function FeedbackForm() {
-Here is a fixed version that uses a regular `name` variable declared in the function that needs it:
+Tässä on korjattu versio, joka käyttää tavallista `name` muuttujaa määriteltynä funktiossa joka sitä tarvitsee:
@@ -1506,7 +1506,7 @@ export default function FeedbackForm() {
-A state variable is only necessary to keep information between re-renders of a component. Within a single event handler, a regular variable will do fine. Don't introduce state variables when a regular variable works well.
+Tilamuuttuja on tarpeellinen pitämään tietoa komponentin renderien välillä. Yksittäisen tapahtumamuuttujan sisällä tavallinen muuttuja riittää. Älä esittele tilamuuttujia kun tavalliset muuttujat toimivat hyvin.
diff --git a/src/content/learn/state-as-a-snapshot.md b/src/content/learn/state-as-a-snapshot.md
index 503b0abb4..30ccd2dd6 100644
--- a/src/content/learn/state-as-a-snapshot.md
+++ b/src/content/learn/state-as-a-snapshot.md
@@ -1,27 +1,29 @@
---
-title: State as a Snapshot
+title: Tila tilannekuvana
---
-State variables might look like regular JavaScript variables that you can read and write to. However, state behaves more like a snapshot. Setting it does not change the state variable you already have, but instead triggers a re-render.
+Tilamuuttujat saattavat näyttää tavallisilta JavaScript muuttujilta, joita voit
+lukea ja joihin voit kirjoittaa. Tilamuuttujat käyttäytyvät enemmän kuin tilannekuvana. Tilannemuuttujan asettaminen ei muuta muuttujaa, joka sinulla jo
+on, vaan sen sijaan käynnistää uudelleenrenderöinnin.
-* How setting state triggers re-renders
-* When and how state updates
-* Why state does not update immediately after you set it
-* How event handlers access a "snapshot" of the state
+* Miten tilamuuttujan asettaminen käynnistää uudelleenrenderöintejä
+* Milloin ja miten tila päivittyy
+* Miksi tila eo päivity heti kun asetat sen
+* Miten tapahtumakäsittelijät saavat "tilannekuvan" tilasta
-## Setting state triggers renders {/*setting-state-triggers-renders*/}
+## Tilan asettaminen käynnistää renderöintejä {/*setting-state-triggers-renders*/}
-You might think of your user interface as changing directly in response to the user event like a click. In React, it works a little differently from this mental model. On the previous page, you saw that [setting state requests a re-render](/learn/render-and-commit#step-1-trigger-a-render) from React. This means that for an interface to react to the event, you need to *update the state*.
+Saatat ajatella käyttöliittymäsi muuttuvan suoraan vastauksena käyttäjän tapahtumiin kuten klikkaukseen. Reactissa se poikkeaa hieman tästä ajattelutavasta. Edellisellä sivulla näit, että [tilan asettaminen pyytää uudelleenrenderöintiä](/learn/render-and-commit#step-1-trigger-a-render) Reactilta. Tämä tarkoittaa, että jotta käyttöliittymä voi reagoida tapahtumaan, sinun tulee *päivittää tilaa*.
-In this example, when you press "send", `setIsSent(true)` tells React to re-render the UI:
+Tässä esimerkissä kun painat "Send" -painiketta, `setIsSent(true)` käskee Reactia renderöimään käyttöliittymä uudelleen:
@@ -61,43 +63,43 @@ label, textarea { margin-bottom: 10px; display: block; }
-Here's what happens when you click the button:
+Tässä mitä tapahtuu kun klikkaat painiketta:
-1. The `onSubmit` event handler executes.
-2. `setIsSent(true)` sets `isSent` to `true` and queues a new render.
-3. React re-renders the component according to the new `isSent` value.
+1. `onSubmit` tapahtumakäsittelijä suoritetaan.
+2. `setIsSent(true)` asettaa `isSent` arvoksi `true` ja lisää renderöinnin jonoon.
+3. React renderöi uudelleen komponentin uuden `isSent` arvon mukaan.
-Let's take a closer look at the relationship between state and rendering.
+Otetaan tarkempi katse tilan ja renderöinnin suhteeseen.
-## Rendering takes a snapshot in time {/*rendering-takes-a-snapshot-in-time*/}
+## Renderöinti ottaa tilannekuvan ajasta {/*rendering-takes-a-snapshot-in-time*/}
-["Rendering"](/learn/render-and-commit#step-2-react-renders-your-components) means that React is calling your component, which is a function. The JSX you return from that function is like a snapshot of the UI in time. Its props, event handlers, and local variables were all calculated **using its state at the time of the render.**
+["Renderöinti"](/learn/render-and-commit#step-2-react-renders-your-components) tarkoittaa, että React kutsuu komponenttiasi, joka on funktio. Funktion palauttama JSX on kuten käyttöliittymän tilannekuva ajasta. Sen propsit, tapahtumakäsittelijät sekä paikalliset muuttujat laskettiin **käyttämällä sen tilaa renderöintihetkellä.**
-Unlike a photograph or a movie frame, the UI "snapshot" you return is interactive. It includes logic like event handlers that specify what happens in response to inputs. React updates the screen to match this snapshot and connects the event handlers. As a result, pressing a button will trigger the click handler from your JSX.
+Toisin kuin valokuva tai elokuvan kehys, UI "tilannekuva", jonka palautat on interaktiivinen. Se sisältää logiikkaa kuten tapahtumakäsittelijöitä, jotka määrittävät mitä tapahtuu vastauksena syötteeseen. React sitten päivittää ruudun vastaamaan tätä tilannekuvaa ja yhdistää tapahtumakäsittelijät. Lopputuloksena painikkeen painaminen käynnistää JSX koodisi tapahtumakäsittelijän.
-When React re-renders a component:
+Kun React renderöi komponentin uudelleen:
-1. React calls your function again.
-2. Your function returns a new JSX snapshot.
-3. React then updates the screen to match the snapshot you've returned.
+1. React kutsuu funktiotasi uudelleen.
+2. Funktiosi palauttaa uuden JSX tilannekuvan.
+3. React sitten päivittää ruudun vastaamaan tilannekuvaa, jonka palautit.
-
-
-
+
+
+
-As a component's memory, state is not like a regular variable that disappears after your function returns. State actually "lives" in React itself--as if on a shelf!--outside of your function. When React calls your component, it gives you a snapshot of the state for that particular render. Your component returns a snapshot of the UI with a fresh set of props and event handlers in its JSX, all calculated **using the state values from that render!**
+Komponentin muistina, tila ei ole kuten tavalliset muuttujat, jotka katoavat kun komponenttisi palautuu. Itse asiassa tila "asuu" itse Reactissa--kuten hyllyllä--komponenttisi ulkopuolella. Kun React kutsuu komponenttiasi, se antaa tilannekuvan tilasta tälle kyseiselle renderöinnille. Komponenttisi palauttaa tilannekuvan käyttöliittymästä uudella joukolla propseja ja tapahtumankäsittelijöitä JSX:ssä, jotka kaikki on laskettu **käyttämällä kyseisen renderöinnin tila-arvoja!**
-
-
-
+
+
+
-Here's a little experiment to show you how this works. In this example, you might expect that clicking the "+3" button would increment the counter three times because it calls `setNumber(number + 1)` three times.
+Tässä pieni kokeilu, joka näyttää miten tämä toimii. Tässä esimerkissä saatat olettaa, että "+3" painikkeen painaminen kasvattaa numera kolme kertaa, koska se kutsuu `setNumber(number + 1)` kolmesti.
-See what happens when you click the "+3" button:
+Katso mitä tapahtuu, kun napsautat "+3"-painiketta:
@@ -127,9 +129,9 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
-Notice that `number` only increments once per click!
+Huomaa, että `number` kasvaa vain kerran per klikkaus!
-**Setting state only changes it for the *next* render.** During the first render, `number` was `0`. This is why, in *that render's* `onClick` handler, the value of `number` is still `0` even after `setNumber(number + 1)` was called:
+**Tilan asettaminen muuttaa sen *seuraavalle* renderille.** Ensimmäisen renderöinnin aikana, `number` oli arvoltaan `0`. Sen takia *tuossa renderöinnissä* `onClick` käsittelijän `number` arvo oli silti `0` jopa sen jälkeen, kun `setNumber(number + 1)` oli kutsuttu:
```js
{
@@ -139,18 +141,18 @@ Notice that `number` only increments once per click!
}}>+3
```
-Here is what this button's click handler tells React to do:
+Tämän painikkeen tapahtumakäsittelijä kertoo Reactille toimimaan seuraavasti:
-1. `setNumber(number + 1)`: `number` is `0` so `setNumber(0 + 1)`.
- - React prepares to change `number` to `1` on the next render.
-2. `setNumber(number + 1)`: `number` is `0` so `setNumber(0 + 1)`.
- - React prepares to change `number` to `1` on the next render.
-3. `setNumber(number + 1)`: `number` is `0` so `setNumber(0 + 1)`.
- - React prepares to change `number` to `1` on the next render.
+1. `setNumber(number + 1)`: `number` on `0` joten `setNumber(0 + 1)`.
+ - React valmistelee muuttamaan `number` arvoksi `1` seuraavalle renderöinnille.
+2. `setNumber(number + 1)`: `number` on `0` joten `setNumber(0 + 1)`.
+ - React valmistelee muuttamaan `number` arvoksi `1` seuraavalle renderöinnille.
+3. `setNumber(number + 1)`: `number` on `0` joten `setNumber(0 + 1)`.
+ - React valmistelee muuttamaan `number` arvoksi `1` seuraavalle renderöinnille.
-Even though you called `setNumber(number + 1)` three times, in *this render's* event handler `number` is always `0`, so you set the state to `1` three times. This is why, after your event handler finishes, React re-renders the component with `number` equal to `1` rather than `3`.
+Vaikka kutsuit `setNumber(number + 1)` kolme kertaa, *tämän renderin* tapahtumakäsittelijän `number` on aina `0`, joten asetit tilan arvoksi `1` kolme kertaa. Tämän vuoksi React renderöi komponentin uudelleen `number` muuttujan ollen `1` eikä `3`.
-You can also visualize this by mentally substituting state variables with their values in your code. Since the `number` state variable is `0` for *this render*, its event handler looks like this:
+Voit myös havainnollistaa tämän myös korvaamalla tilamuuttujat niiden arovilla koodissa. Koska tilamuuttuja `number` on `0` *tässä renderöinnissä*, sen tapahtumakäsittelijä näyttää tältä:
```js
{
@@ -160,7 +162,7 @@ You can also visualize this by mentally substituting state variables with their
}}>+3
```
-For the next render, `number` is `1`, so *that render's* click handler looks like this:
+Seuraavassa renderöinnissä `number` on `1`, joten *tämän renderöinnin* tapahtumakäsittelijä näyttää tältä:
```js
{
@@ -170,11 +172,11 @@ For the next render, `number` is `1`, so *that render's* click handler looks lik
}}>+3
```
-This is why clicking the button again will set the counter to `2`, then to `3` on the next click, and so on.
+Tämän vuoksi painikkeen klikkaaminen asettaa laskurin arvoksi `2`, ja sitten seuraavalla klikkauksella `3` ja niin edelleen.
-## State over time {/*state-over-time*/}
+## Tila ajan myötä {/*state-over-time*/}
-Well, that was fun. Try to guess what clicking this button will alert:
+Noh, se oli hauskaa. Kokeile veikata mitä painikkeen klikkaaminen ilmoittaa:
@@ -203,14 +205,14 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
-If you use the substitution method from before, you can guess that the alert shows "0":
+Jos sovellat aiemmin mainittua korvausmenetelmää, voit veikata, että ilmoituksessa lukee "0":
```js
setNumber(0 + 5);
alert(0);
```
-But what if you put a timer on the alert, so it only fires _after_ the component re-rendered? Would it say "0" or "5"? Have a guess!
+Mutta entä jos laitat ajastimen ilmoitukseen, jotta sitä kutsutaan komponentin uudelleen renderöinnin _jälkeen_? Lukisiko siinä "0" vai "5"? Koita veikata!
@@ -241,7 +243,7 @@ h1 { display: inline-block; margin: 10px; width: 30px; text-align: center; }
-Surprised? If you use the substitution method, you can see the "snapshot" of the state passed to the alert.
+Yllätyitkö? Jos sovellat aiemmin mainittua korvausmenetelmää, näet, että "tilannekuva" tilasta välitettiin ilmoitukseen.
```js
setNumber(0 + 5);
@@ -250,16 +252,16 @@ setTimeout(() => {
}, 3000);
```
-The state stored in React may have changed by the time the alert runs, but it was scheduled using a snapshot of the state at the time the user interacted with it!
+Reactiin tallennettu tila on saattanut muuttua, kun ilmoitus suoritetaan, mutta se ajoitettiin käyttämällä tilannekuvaa tilasta sillä hetkellä, kun käyttäjä oli vuorovaikutuksessa sen kanssa!
-**A state variable's value never changes within a render,** even if its event handler's code is asynchronous. Inside *that render's* `onClick`, the value of `number` continues to be `0` even after `setNumber(number + 5)` was called. Its value was "fixed" when React "took the snapshot" of the UI by calling your component.
+**Tilamuuttujan arvo ei koskaan muutu renderöinnin aikana,** vaikka sen tapahtumakäsittelijän koodi olisi asynkroninen. *Tuon renderöinnin* `onClick`:n sisällä `number`:n arvo on edelleen `0`, vaikka `setNumber(number + 5)` kutsuttiin. Sen arvo "kiinnitettiin", kun React "otti tilannekuvan" käyttöliittymästä kutsumalla komponenttiasi.
-Here is an example of how that makes your event handlers less prone to timing mistakes. Below is a form that sends a message with a five-second delay. Imagine this scenario:
+Tässä on esimerkki siitä, miten tämä tekee tapahtumankäsittelijöistäsi vähemmän alttiita ajoitusvirheille. Alla on lomake, joka lähettää viestin viiden sekunnin viiveellä. Kuvittele tämä skenaario:
-1. You press the "Send" button, sending "Hello" to Alice.
-2. Before the five-second delay ends, you change the value of the "To" field to "Bob".
+1. Painat "Send"-painiketta, lähettäen "Hello" Aliisalle.
+2. Ennen viiden sekunnin viiveen päättymistä, muutat "To" kentän arvoksi "Bob".
-What do you expect the `alert` to display? Would it display, "You said Hello to Alice"? Or would it display, "You said Hello to Bob"? Make a guess based on what you know, and then try it:
+Mitä odotat, että `alert` näyttää? Näyttäisikö se, "You said Hello to Alice"? Vai, "You said Hello to Bob"? Tee arvaus sen perusteella mitä tiedät ja kokeile sitten:
@@ -305,19 +307,19 @@ label, textarea { margin-bottom: 10px; display: block; }
-**React keeps the state values "fixed" within one render's event handlers.** You don't need to worry whether the state has changed while the code is running.
+**React pitää tilan arvot "kiinteinä" renderöinnin tapahtumakäsittelijöiden sisällä.** Sinun ei tarvitse huolehtia siitä, onko tila muuttunut koodin suorituksen aikana.
-But what if you wanted to read the latest state before a re-render? You'll want to use a [state updater function](/learn/queueing-a-series-of-state-updates), covered on the next page!
+Entä jos haluat lukea viimeisimmän tilan ennen uudelleen renderöintiä? Haluat käyttää [tilapäivitysfunktiota](/learn/queueing-a-series-of-state-updates), jota käsitellään seuraavalla sivulla!
-* Setting state requests a new render.
-* React stores state outside of your component, as if on a shelf.
-* When you call `useState`, React gives you a snapshot of the state *for that render*.
-* Variables and event handlers don't "survive" re-renders. Every render has its own event handlers.
-* Every render (and functions inside it) will always "see" the snapshot of the state that React gave to *that* render.
-* You can mentally substitute state in event handlers, similarly to how you think about the rendered JSX.
-* Event handlers created in the past have the state values from the render in which they were created.
+* Tilan asettaminen pyytää uutta renderöintiä.
+* React tallentaa tilan komponenttisi ulkopuolelle, ikään kuin hyllyyn.
+* Kun kutsut `useState`:a, React antaa sinulle tilannekuvan tilasta *tässä renderöinnissä*.
+* Muuttujat ja tapahtumankäsittelijät eivät "selviä" uudelleenlatauksista. Jokaisella renderöinnillä on omat tapahtumankäsittelijänsä.
+* Jokainen renderöinti (ja sen sisällä olevat funktiot) "näkevät" aina tilannekuvan tilasta, jonka React antoi *tälle* renderöinnille.
+* Voit havainnollistaa tilan tapahtumankäsittelijöissä samalla tavalla kuin ajattelet renderöidystä JSX:stä.
+* Aikaisemmin luoduilla tapahtumankäsittelijöillä on sen renderöinnin tila-arvot, jossa ne luotiin.
@@ -325,16 +327,16 @@ But what if you wanted to read the latest state before a re-render? You'll want
-#### Implement a traffic light {/*implement-a-traffic-light*/}
+#### Toteuta liikennevalot {/*implement-a-traffic-light*/}
-Here is a crosswalk light component that toggles when the button is pressed:
+Tässä on suojatien valokomponentti, joka vaihtuu tilasta toiseen, kun painiketta painetaan:
```js
import { useState } from 'react';
-export default function TrafficLight() {
+export default function Liikennevalo() {
const [walk, setWalk] = useState(true);
function handleClick() {
@@ -344,12 +346,12 @@ export default function TrafficLight() {
return (
<>
- Change to {walk ? 'Stop' : 'Walk'}
+ Vaihda: {walk ? 'Pysähdy' : 'Kävele'}
- {walk ? 'Walk' : 'Stop'}
+ {walk ? 'Kävele' : 'Pysähdy'}
>
);
@@ -362,13 +364,13 @@ h1 { margin-top: 20px; }
-Add an `alert` to the click handler. When the light is green and says "Walk", clicking the button should say "Stop is next". When the light is red and says "Stop", clicking the button should say "Walk is next".
+Lisää `alert` klikkauksen tapahtumakäsittelijään. Kun valo on vihreä se ja sanoo "Kävele", painikkeen painamisen tulisi ilmoittaa "Seuraavaksi pysähdytään". Kun valo on punainen ja sanoo "Pysähdy", painikkeen painamisen tulisi ilmoittaa "Seuraavaksi kävellään".
-Does it make a difference whether you put the `alert` before or after the `setWalk` call?
+Onko sillä merkitystä laitatko `alert`:n enne vai jälkeen `setWalk` kutsua?
-Your `alert` should look like this:
+Sinun `alert`:n pitäisi näyttää tältä:
@@ -380,18 +382,18 @@ export default function TrafficLight() {
function handleClick() {
setWalk(!walk);
- alert(walk ? 'Stop is next' : 'Walk is next');
+ alert(walk ? 'Seuraavaksi pysähdytään' : 'Seuraavaksi kävellään');
}
return (
<>
- Change to {walk ? 'Stop' : 'Walk'}
+ Vaihda: {walk ? 'Pysähdy' : 'Kävele'}
- {walk ? 'Walk' : 'Stop'}
+ {walk ? 'Kävele' : 'Pysähdy'}
>
);
@@ -404,31 +406,30 @@ h1 { margin-top: 20px; }
-Whether you put it before or after the `setWalk` call makes no difference. That render's value of `walk` is fixed. Calling `setWalk` will only change it for the *next* render, but will not affect the event handler from the previous render.
+Riippumatta siitä laitatko sen ennen vai jälkeen `setWalk` kutsun, sillä ei merkitystä. Tämän renderin `walk` tilan arvo on "kiinteä". `setWalk` kutsuminen muuttaa sen vain *seuraavalle* renderöinnille, mutta se ei vaikuta aikaisempien renderien tapahtumakäsittelijöihin.
-This line might seem counter-intuitive at first:
+Tämä rivi saattaa vaikuttaa epäintuitiiviselta aluksi:
```js
-alert(walk ? 'Stop is next' : 'Walk is next');
+alert(walk ? 'Seuraavaksi pysähdytään' : 'Seuraavaksi kävellään');
```
-But it makes sense if you read it as: "If the traffic light shows 'Walk now', the message should say 'Stop is next.'" The `walk` variable inside your event handler matches that render's value of `walk` and does not change.
+Mutta siinä on järkeä, kun luet sen seuraavasti: "Jos liikennevalon väri sanoo 'Kävele', ilmoituksen tulisi olla 'Seuraavaksi pysähdytään.'" Tapahtumakäsittelijässäsi oleva `walk` -muuttuja vastaa kyseisen renderöinnin `walk`-arvoa, eikä se muutu.
-You can verify that this is correct by applying the substitution method. When `walk` is `true`, you get:
+Voit tarkistaa, että tämä on oikein soveltamalla korvausmenetelmää. Kun `walk` on `true`, saat:
```js
{
setWalk(false);
- alert('Stop is next');
+ alert('Seuraavaksi pysähdytään');
}}>
- Change to Stop
+ Vaihda: Pysähdy
- Walk
+ Kävele
```
-
-So clicking "Change to Stop" queues a render with `walk` set to `false`, and alerts "Stop is next".
+Joten klikkaamalla "Vaihda pysähdykseen" jonotetaan renderöinti, jossa `walk` muuttujan arvoksi on asetettu `false`, ja näytetään ilmoitus "Seuraavaksi pysähdytään".
diff --git a/src/content/learn/synchronizing-with-effects.md b/src/content/learn/synchronizing-with-effects.md
index 24b9f9eb1..788d74820 100644
--- a/src/content/learn/synchronizing-with-effects.md
+++ b/src/content/learn/synchronizing-with-effects.md
@@ -1,97 +1,97 @@
---
-title: 'Synchronizing with Effects'
+title: Synkronointi Effecteilla
---
-Some components need to synchronize with external systems. For example, you might want to control a non-React component based on the React state, set up a server connection, or send an analytics log when a component appears on the screen. *Effects* let you run some code after rendering so that you can synchronize your component with some system outside of React.
+Joidenkin komponenttien täytyy synkronoida ulkoisten järjestelmien kanssa. Esimerkiksi saatat haluta hallita ei-React-komponenttia perustuen Reactin tilaan, asettaa palvelinyhteyden tai lähettää analytiikkalokeja, kun komponentti näkyy näytöllä. *Effectit* mahdollistavat koodin suorittamisen renderöinnin jälkeen, jotta voit synkronoida komponentin jonkin ulkoisen järjestelmän kanssa Reactin ulkopuolella.
-- What Effects are
-- How Effects are different from events
-- How to declare an Effect in your component
-- How to skip re-running an Effect unnecessarily
-- Why Effects run twice in development and how to fix them
+- Mitä Effectit ovat
+- Miten Effectit eroavat tapahtumista
+- Miten määrittelet Effecti komponentissasi
+- Miten ohitat Effectin tarpeettoman suorittamisen
+- Miksi Effectit suoritetetaan kahdesti kehitysympäristössä ja miten sen voi korjata
-## What are Effects and how are they different from events? {/*what-are-effects-and-how-are-they-different-from-events*/}
+## Mitä Effectit ovat ja miten ne eroavat tapahtumista? {/*what-are-effects-and-how-are-they-different-from-events*/}
-Before getting to Effects, you need to be familiar with two types of logic inside React components:
+Ennen kuin siirrytään Effecteihin, tutustutaan kahdenlaiseen logiikkaan React-komponenteissa:
-- **Rendering code** (introduced in [Describing the UI](/learn/describing-the-ui)) lives at the top level of your component. This is where you take the props and state, transform them, and return the JSX you want to see on the screen. [Rendering code must be pure.](/learn/keeping-components-pure) Like a math formula, it should only _calculate_ the result, but not do anything else.
+- **Renderöintikoodi** (esitellään [Käyttöliittymän kuvauksessa](/learn/describing-the-ui)) elää komponentin yläpuolella. Tässä on paikka missä otat propsit ja tilan, muunnet niitä ja palautat JSX:ää, jonka haluat nähdä näytöllä. [Renderöintikoodin on oltava puhdasta.](/learn/keeping-components-pure) Kuten matemaattinen kaava, sen tulisi vain _laskea_ tulos, mutta ei tehdä mitään muuta.
-- **Event handlers** (introduced in [Adding Interactivity](/learn/adding-interactivity)) are nested functions inside your components that *do* things rather than just calculate them. An event handler might update an input field, submit an HTTP POST request to buy a product, or navigate the user to another screen. Event handlers contain ["side effects"](https://en.wikipedia.org/wiki/Side_effect_(computer_science)) (they change the program's state) caused by a specific user action (for example, a button click or typing).
+- **Tapahtumakäsittelijät** (esitellään [Interaktiivisuuden lisäämisessä](/learn/adding-interactivity)) ovat komponenttien sisäisiä funktioita, jotka *tekevät* asioita sen sijaan, että vain laskisivat asioita. Tapahtumakäsittelijä saattavat päivittää syöttökenttää, lähettää HTTP POST -pyyntöjä ostaakseen tuoteen tai ohjata käyttäjän toiselle näytölle. Tapahtumakäsittelijät sisältävät ["sivuvaikutuksia"](https://en.wikipedia.org/wiki/Side_effect_(computer_science)) (ne muuttavat ohjelman tilaa) ja aiheutuvat tietystä käyttäjän toiminnasta (esimerkiksi painikkeen napsauttamisesta tai kirjoittamisesta).
-Sometimes this isn't enough. Consider a `ChatRoom` component that must connect to the chat server whenever it's visible on the screen. Connecting to a server is not a pure calculation (it's a side effect) so it can't happen during rendering. However, there is no single particular event like a click that causes `ChatRoom` to be displayed.
+Joskus tämä ei riitä. Harkitse `ChatRoom` -komponenttia, jonka täytyy yhdistää keskustelupalvelimeen, kun se näkyy näytöllä. Palvelimeen yhdistäminen ei ole puhdas laskenta (se on sivuvaikutus), joten se ei voi tapahtua renderöinnin aikana. Kuitenkaan ei ole yhtä tiettyä tapahtumaa, kuten napsautusta, joka aiheuttaisi `ChatRoom` -komponentin näkymisen.
-***Effects* let you specify side effects that are caused by rendering itself, rather than by a particular event.** Sending a message in the chat is an *event* because it is directly caused by the user clicking a specific button. However, setting up a server connection is an *Effect* because it should happen no matter which interaction caused the component to appear. Effects run at the end of a [commit](/learn/render-and-commit) after the screen updates. This is a good time to synchronize the React components with some external system (like network or a third-party library).
+***Effectien* avulla voit määritellä sivuvaikutukset, jotka johtuvat renderöinnistä itsestään, eikä tietystä tapahtumasta.** Viestin lähettäminen keskustelussa on *tapahtuma*, koska se aiheutuu suoraan käyttäjän napsauttamasta tiettyä painiketta. Kuitenkin palvelimen yhdistäminen on *effect*, koska se on tehtävä riippumatta siitä, mikä vuorovaikutus aiheutti komponentin näkyvyyden. Effectit suoritetaan [renderöintiprosessin](/learn/render-and-commit) lopussa näytön päivityksen jälkeen. Tässä on hyvä aika synkronoida React-komponentit jonkin ulkoisen järjestelmän kanssa (kuten verkon tai kolmannen osapuolen kirjaston).
-Here and later in this text, capitalized "Effect" refers to the React-specific definition above, i.e. a side effect caused by rendering. To refer to the broader programming concept, we'll say "side effect".
+Tässä ja myöhemmin tekstissä, "Effect":llä viittaamme Reactin määritelmään, eli sivuvaikutukseen, joka aiheutuu renderöinnistä. Viittaaksemme laajempaan ohjelmointikäsitteeseen, sanomme "sivuvaikutus".
-## You might not need an Effect {/*you-might-not-need-an-effect*/}
+## Et välttämättä tarvitse Effectia {/*you-might-not-need-an-effect*/}
-**Don't rush to add Effects to your components.** Keep in mind that Effects are typically used to "step out" of your React code and synchronize with some *external* system. This includes browser APIs, third-party widgets, network, and so on. If your Effect only adjusts some state based on other state, [you might not need an Effect.](/learn/you-might-not-need-an-effect)
+**Älä kiiruhda lisäämään Effecteja komponentteihisi.** Pidä mielessä, että Effectit ovat tyypillisesti tapa "astua ulos" React-koodistasi ja synkronoida jonkin *ulkoisen* järjestelmän kanssa. Tämä sisältää selaimen API:t, kolmannen osapuolen pienoisohjelmat, verkon jne. Jos Effectisi vain muuttaa tilaa perustuen toiseen tilaan, [voit ehkä jättää Effectin pois.](/learn/you-might-not-need-an-effect)
-## How to write an Effect {/*how-to-write-an-effect*/}
+## Miten kirjoitat Effectin {/*how-to-write-an-effect*/}
-To write an Effect, follow these three steps:
+Kirjoittaaksesi Effectin, seuraa näitä kolmea vaihetta:
-1. **Declare an Effect.** By default, your Effect will run after every render.
-2. **Specify the Effect dependencies.** Most Effects should only re-run *when needed* rather than after every render. For example, a fade-in animation should only trigger when a component appears. Connecting and disconnecting to a chat room should only happen when the component appears and disappears, or when the chat room changes. You will learn how to control this by specifying *dependencies.*
-3. **Add cleanup if needed.** Some Effects need to specify how to stop, undo, or clean up whatever they were doing. For example, "connect" needs "disconnect", "subscribe" needs "unsubscribe", and "fetch" needs either "cancel" or "ignore". You will learn how to do this by returning a *cleanup function*.
+1. **Määrittele Effect.** Oletuksena, Effectisi suoritetaan jokaisen renderöinnin jälkeen.
+2. **Määrittele Effectin riippuvuudet.** Useimmat Effectit pitäisi suorittaa vain *tarvittaessa* sen sijaan, että ne suoritettaisiin jokaisen renderöinnin jälkeen. Esimerkiksi fade-in -animaatio pitäisi käynnistyä vain, kun komponentti ilmestyy. Keskusteluhuoneeseen yhdistäminen ja sen katkaisu pitäisi tapahtua vain, kun komponentti ilmestyy ja häviää tai kun keskusteluhuone muuttuu. Opit hallitsemaan tätä määrittämällä *riippuvuudet.*
+3. **Lisää puhdistus, jos tarpeen.** Joidenkin Effectien täytyy määrittää, miten ne pysäytetään, peruutetaan, tai puhdistavat mitä ne ovat tehneet. Esimerkiksi "yhdistys" tarvitsee "katkaisun", "tila" tarvitsee "peruuta tilaus" ja "hae" tarvitsee joko "peruuta" tai "jätä huomiotta". Opit tekemään tämän palauttamalla *puhdistusfunktion*.
-Let's look at each of these steps in detail.
+Katsotaan näitä vaiheita yksityiskohtaisesti.
-### Step 1: Declare an Effect {/*step-1-declare-an-effect*/}
+### 1. Vaihe: Määrittele Effect {/*step-1-declare-an-effect*/}
-To declare an Effect in your component, import the [`useEffect` Hook](/reference/react/useEffect) from React:
+Määritelläksesi Effectin komponentissasi, tuo [`useEffect` Hook](/reference/react/useEffect) Reactista:
```js
import { useEffect } from 'react';
```
-Then, call it at the top level of your component and put some code inside your Effect:
+Sitten kutsu sitä komponentin yläpuolella ja laita koodia Effectin sisään:
```js {2-4}
function MyComponent() {
useEffect(() => {
- // Code here will run after *every* render
+ // Koodi täällä suoritetaan *jokaisen* renderöinnin jälkeen
});
return
;
}
```
-Every time your component renders, React will update the screen *and then* run the code inside `useEffect`. In other words, **`useEffect` "delays" a piece of code from running until that render is reflected on the screen.**
+Joka kerta kun komponenttisi renderöityy, React päivittää ruudun *ja sitten* suorittaa koodin `useEffect`:n sisällä. Toisin sanoen, **`useEffect` "viivästää" koodin suorittamista, kunnes renderöinti on näkyvissä ruudulla.**
-Let's see how you can use an Effect to synchronize with an external system. Consider a `` React component. It would be nice to control whether it's playing or paused by passing an `isPlaying` prop to it:
+Katsotaan miten voit käyttää Effectia synkronoidaksesi ulkoisen järjestelmän kanssa. Harkitse `` React komponenttia. Olisi mukavaa kontrolloida, onko video toistossa vai pysäytettynä, välittämällä `isPlaying` propsin sille:
```js
;
```
-Your custom `VideoPlayer` component renders the built-in browser [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video) tag:
+Sinun mukautettu `VideoPlayer` komponentti renderöi selaimen sisäänrakennetun [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video) tagin:
```js
function VideoPlayer({ src, isPlaying }) {
- // TODO: do something with isPlaying
+ // TODO: tee jotain isPlaying:lla
return ;
}
```
-However, the browser `` tag does not have an `isPlaying` prop. The only way to control it is to manually call the [`play()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play) and [`pause()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/pause) methods on the DOM element. **You need to synchronize the value of `isPlaying` prop, which tells whether the video _should_ currently be playing, with calls like `play()` and `pause()`.**
+Kuitenkaan selaimen `` tagissa ei ole `isPlaying` proppia. Ainoa tapa ohjata sitä on manuaalisesti kutsua [`play()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play) ja [`pause()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/pause) metodeja DOM elementillä. **Sinun täytyy synkronoida `isPlaying` propin arvo, joka kertoo, pitäisikö video _nyt_ toistaa, imperatiivisilla kutsuilla kuten `play()` ja `pause()`.**
-We'll need to first [get a ref](/learn/manipulating-the-dom-with-refs) to the `` DOM node.
+Meidän täytyy ensiksi hakea [ref](/learn/manipulating-the-dom-with-refs) ``:n DOM noodiin.
-You might be tempted to try to call `play()` or `pause()` during rendering, but that isn't correct:
+Saattaa olla houkuttelevaa kutsua `play()` tai `pause()` metodeja renderöinnin aikana, mutta se ei ole oikein:
@@ -102,9 +102,9 @@ function VideoPlayer({ src, isPlaying }) {
const ref = useRef(null);
if (isPlaying) {
- ref.current.play(); // Calling these while rendering isn't allowed.
+ ref.current.play(); // Tämän kutsuminen renderöinnin aikana ei ole sallittua.
} else {
- ref.current.pause(); // Also, this crashes.
+ ref.current.pause(); // Tämä myöskin kaatuu.
}
return ;
@@ -133,11 +133,11 @@ video { width: 250px; }
-The reason this code isn't correct is that it tries to do something with the DOM node during rendering. In React, [rendering should be a pure calculation](/learn/keeping-components-pure) of JSX and should not contain side effects like modifying the DOM.
+Syy miksi tämä koodi ei ole oikein on, että se koittaa tehdä jotain DOM noodilla kesken renderöinnin. Reactissa [renderöinnin tulisi olla puhdas laskelma](/learn/keeping-components-pure) JSX:stä ja sen ei tulisi sisältää sivuvaikutuksia kuten DOM:n muuttamista.
-Moreover, when `VideoPlayer` is called for the first time, its DOM does not exist yet! There isn't a DOM node yet to call `play()` or `pause()` on, because React doesn't know what DOM to create until you return the JSX.
+Lisäksi, kun `VideoPlayer` kutsutaan ensimmäistä kertaa, sen DOM ei vielä ole olemassa! Ei ole vielä DOM noodia josta kutsua `play()` tai `pause()` koska React ei tiedä mitä DOM:ia luoda ennen kuin palautat JSX:n.
-The solution here is to **wrap the side effect with `useEffect` to move it out of the rendering calculation:**
+Ratkaisu tässä on **kääriä sivuvaikutus `useEffectilla` ja siirtää se pois renderöintilaskusta:**
```js {6,12}
import { useEffect, useRef } from 'react';
@@ -157,11 +157,11 @@ function VideoPlayer({ src, isPlaying }) {
}
```
-By wrapping the DOM update in an Effect, you let React update the screen first. Then your Effect runs.
+Käärimällä DOM päivitys Effectiin, annat Reactin päivittää ensin ruudun. Sitten Effectisi suoritetaan.
-When your `VideoPlayer` component renders (either the first time or if it re-renders), a few things will happen. First, React will update the screen, ensuring the `` tag is in the DOM with the right props. Then React will run your Effect. Finally, your Effect will call `play()` or `pause()` depending on the value of `isPlaying`.
+Kun `VideoPlayer` komponenttisi renderöityy (joko ensimmäistä kertaa tai jos se renderöityy uudelleen), tapahtuu muutamia asioita. Ensimmäiseksi React päivittää ruudun, varmistaen että `` tagi on DOM:issa oikeilla propseilla. Sitten React suorittaa Effectisi. Lopuksi, Effectisi kutsuu `play()` tai `pause()` riippuen `isPlaying` propin arvosta.
-Press Play/Pause multiple times and see how the video player stays synchronized to the `isPlaying` value:
+Paina Play/Pause useita kertoja ja katso miten videoplayer pysyy synkronoituna `isPlaying` arvon kanssa:
@@ -205,13 +205,13 @@ video { width: 250px; }
-In this example, the "external system" you synchronized to React state was the browser media API. You can use a similar approach to wrap legacy non-React code (like jQuery plugins) into declarative React components.
+Tässä esimerkissä "ulkoinen järjestelmä" jonka kanssa synkronoit Reactin tilan oli selaimen media API. Voit käyttää samanlaista lähestymistapaa kääriäksesi legacy ei-React koodin (kuten jQuery pluginit) deklaratiivisiin React komponentteihin.
-Note that controlling a video player is much more complex in practice. Calling `play()` may fail, the user might play or pause using the built-in browser controls, and so on. This example is very simplified and incomplete.
+Huomaa, että videoplayerin ohjaaminen on paljon monimutkaisempaa käytännössä. `play()` kutsu voi epäonnistua, käyttäjä voi toistaa tai pysäyttää videon käyttämällä selaimen sisäänrakennettuja ohjauselementtejä, jne. Tämä esimerkki on hyvin yksinkertaistettu ja puutteellinen.
-By default, Effects run after *every* render. This is why code like this will **produce an infinite loop:**
+Oletuksena Effectit suoritetaan *jokaisen* renderöinnin jälkeen. Tämä on syy miksi seuraavanlainen koodi **tuottaa loputtoman silmukan:**
```js
const [count, setCount] = useState(0);
@@ -220,20 +220,20 @@ useEffect(() => {
});
```
-Effects run as a *result* of rendering. Setting state *triggers* rendering. Setting state immediately in an Effect is like plugging a power outlet into itself. The Effect runs, it sets the state, which causes a re-render, which causes the Effect to run, it sets the state again, this causes another re-render, and so on.
+Effectit suoritetaan renderöinnin *johdosta*. Tilan asettaminen *aiheuttaa* renderöinnin. Tilan asettaminen välittömästi Effectissä on kuin pistäisi jatkojohdon kiinni itseensä. Effect suoritetaan, se asettaa tilan, joka aiheuttaa uudelleen renderöinnin, joka aiheuttaa Effectin suorittamisen, joka asettaa tilan uudelleen, joka aiheuttaa uudelleen renderöinnin, ja niin edelleen.
-Effects should usually synchronize your components with an *external* system. If there's no external system and you only want to adjust some state based on other state, [you might not need an Effect.](/learn/you-might-not-need-an-effect)
+Effectien tulisi yleensä synkronoida komponenttisi *ulkopuolisen* järjestelmän kanssa. Jos ei ole ulkopuolista järjestelmää ja haluat vain muuttaa tilaa perustuen toiseen tilaan, [voit ehkä jättää Effectin pois.](/learn/you-might-not-need-an-effect)
-### Step 2: Specify the Effect dependencies {/*step-2-specify-the-effect-dependencies*/}
+### 2. Vaihe: Määrittele Effectin riippuvuudet {/*step-2-specify-the-effect-dependencies*/}
-By default, Effects run after *every* render. Often, this is **not what you want:**
+Oletuksena Effectit toistetaan *jokaisen* renderöinnin jälkeen. Usein tämä **ei ole mitä haluat:**
-- Sometimes, it's slow. Synchronizing with an external system is not always instant, so you might want to skip doing it unless it's necessary. For example, you don't want to reconnect to the chat server on every keystroke.
-- Sometimes, it's wrong. For example, you don't want to trigger a component fade-in animation on every keystroke. The animation should only play once when the component appears for the first time.
+- Joskus, se on hidas. Synkronointi ulkoisen järjestelmän kanssa ei aina ole nopeaa, joten haluat ehkä ohittaa sen, ellei sitä ole tarpeen. Esimerkiksi, et halua yhdistää chat palvelimeen jokaisen näppäinpainalluksen jälkeen.
+- Joksus, se on väärin. Esimerkiksi, et halua käynnistää komponentin fade-in animaatiota jokaisen näppäinpainalluksen jälkeen. Animaation pitäisi toistua pelkästään kerran kun komponentti ilmestyy ensimmäisellä kerralla.
-To demonstrate the issue, here is the previous example with a few `console.log` calls and a text input that updates the parent component's state. Notice how typing causes the Effect to re-run:
+Havainnollistaaksemme ongelmaa, tässä on edellinen esimerkki muutamalla `console.log` kutsulla ja tekstikentällä, joka päivittää vanhemman komponentin tilaa. Huomaa miten kirjoittaminen aiheuttaa Effectin uudelleen suorittamisen:
@@ -281,7 +281,7 @@ video { width: 250px; }
-You can tell React to **skip unnecessarily re-running the Effect** by specifying an array of *dependencies* as the second argument to the `useEffect` call. Start by adding an empty `[]` array to the above example on line 14:
+Voit kertoa Reactin **ohittamaan tarpeettoman Effectin uudelleen suorittamisen** määrittelemällä *riippuvuus* taulukon toisena argumenttina `useEffect` kutsulle. Aloita lisäämällä tyhjä `[]` taulukko ylläolevaan esimerkkiin riville 14:
```js {3}
useEffect(() => {
@@ -289,7 +289,13 @@ You can tell React to **skip unnecessarily re-running the Effect** by specifying
}, []);
```
-You should see an error saying `React Hook useEffect has a missing dependency: 'isPlaying'`:
+Sinun tulisi nähdä virhe, jossa lukee `React Hook useEffect has a missing dependency: 'isPlaying'`:
+
+```js
+ useEffect(() => {
+ // ...
+ }, []);
+```
@@ -307,7 +313,7 @@ function VideoPlayer({ src, isPlaying }) {
console.log('Calling video.pause()');
ref.current.pause();
}
- }, []); // This causes an error
+ }, []); // Tämä aiheuttaa virheen
return ;
}
@@ -337,19 +343,20 @@ video { width: 250px; }
-The problem is that the code inside of your Effect *depends on* the `isPlaying` prop to decide what to do, but this dependency was not explicitly declared. To fix this issue, add `isPlaying` to the dependency array:
+Ongelma on, että effectin sisällä oleva koodi *riippuu* `isPlaying` propsin arvosta päättääkseen mitä tehdä, mutta tätä riippuvuutta ei ole määritelty. Korjataksesi tämän ongelman, lisää `isPlaying` riippuvuustaulukkoon:
+
```js {2,7}
useEffect(() => {
- if (isPlaying) { // It's used here...
+ if (isPlaying) { // Sitä käytetään tässä...
// ...
} else {
// ...
}
- }, [isPlaying]); // ...so it must be declared here!
+ }, [isPlaying]); // ...joten se täytyy määritellä täällä!
```
-Now all dependencies are declared, so there is no error. Specifying `[isPlaying]` as the dependency array tells React that it should skip re-running your Effect if `isPlaying` is the same as it was during the previous render. With this change, typing into the input doesn't cause the Effect to re-run, but pressing Play/Pause does:
+Nyt kaikki riippuvuudet on määritelty, joten virheitä ei ole. `[isPlaying]` riippuvuustaulukon määrittäminen kertoo Reactille, että se pitäisi ohittaa Effectin uudelleen suorittaminen jos `isPlaying` on sama kuin se oli edellisellä renderöinnillä. Tämän muutoksen jälkeen, tekstikenttään kirjoittaminen ei aiheuta Effectin uudelleen suorittamista, mutta Play/Pause painikkeen painaminen aiheuttaa:
@@ -397,37 +404,38 @@ video { width: 250px; }
-The dependency array can contain multiple dependencies. React will only skip re-running the Effect if *all* of the dependencies you specify have exactly the same values as they had during the previous render. React compares the dependency values using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. See the [`useEffect` reference](/reference/react/useEffect#reference) for details.
+Riippuvuustaulukko voi sisältää useita riippuvuuksia. React ohittaa Effectin uudelleen suorittamisen *vain* jos *kaikki* riippuvuudet ovat samat kuin edellisellä renderöinnillä. React vertaa riippuvuuksien arvoja käyttäen [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) vertailua. Katso [`useEffect` API viittaus](/reference/react/useEffect#reference) lisätietoja varten.
-**Notice that you can't "choose" your dependencies.** You will get a lint error if the dependencies you specified don't match what React expects based on the code inside your Effect. This helps catch many bugs in your code. If you don't want some code to re-run, [*edit the Effect code itself* to not "need" that dependency.](/learn/lifecycle-of-reactive-effects#what-to-do-when-you-dont-want-to-re-synchronize)
+**Huomaa, että et voi "valita" riippuvuuksiasi.** Jos määrittelemäsi riippuvuudet eivät vastaa Reactin odottamia riippuvuuksia, saat linter virheen. Tämä auttaa löytämään useita virheitä koodissasi. Jos Effect käyttää jotain arvoa, mutta *et* halua suorittaa Effectiä uudelleen kun se muuttuu, sinun täytyy [*muokata Effectin koodia itse* jotta se ei "tarvitse" tätä riippuvuutta.](/learn/lifecycle-of-reactive-effects#what-to-do-when-you-dont-want-to-re-synchronize)
-The behaviors without the dependency array and with an *empty* `[]` dependency array are different:
+Käyttäytyminen *ilman* riippuvuustaulukkoa ja *tyhjällä* `[]` riippuvuustaulukolla ovat hyvin erilaisia:
-```js {3,7,11}
+```js {3,7,12}
useEffect(() => {
- // This runs after every render
+ // Tämä suoritetaan joka kerta kun komponentti renderöidään
});
useEffect(() => {
- // This runs only on mount (when the component appears)
+ // Tämä suoritetaan vain mountattaessa (kun komponentti ilmestyy)
}, []);
useEffect(() => {
- // This runs on mount *and also* if either a or b have changed since the last render
+ // Tämä suoritetaan mountattaessa *ja myös* jos a tai b ovat
+ // muuttuneet viime renderöinnin jälkeen
}, [a, b]);
```
-We'll take a close look at what "mount" means in the next step.
+Katsomme seuraavassa vaiheessa tarkemmin mitä "mount" tarkoittaa.
-#### Why was the ref omitted from the dependency array? {/*why-was-the-ref-omitted-from-the-dependency-array*/}
+#### Miksi ref oli jätetty riippuvuustaulukosta pois? {/*why-was-the-ref-omitted-from-the-dependency-array*/}
-This Effect uses _both_ `ref` and `isPlaying`, but only `isPlaying` is declared as a dependency:
+Tämä Effecti käyttää _sekä_ `ref` että `isPlaying`:ä, mutta vain `isPlaying` on määritelty riippuvuustaulukkoon:
```js {9}
function VideoPlayer({ src, isPlaying }) {
@@ -441,7 +449,7 @@ function VideoPlayer({ src, isPlaying }) {
}, [isPlaying]);
```
-This is because the `ref` object has a *stable identity:* React guarantees [you'll always get the same object](/reference/react/useRef#returns) from the same `useRef` call on every render. It never changes, so it will never by itself cause the Effect to re-run. Therefore, it does not matter whether you include it or not. Including it is fine too:
+Tämä tapahtuu koska `ref` oliolla on *vakaa identiteetti:* React takaa [että saat aina saman olion](/reference/react/useRef#returns) samasta `useRef` kutsusta joka renderöinnillä. Se ei koskaan muutu, joten se ei koskaan itsessään aiheuta Effectin uudelleen suorittamista. Siksi ei ole merkityksellistä onko se määritelty riippuvuustaulukkoon vai ei. Sen sisällyttäminen on myös ok:
```js {9}
function VideoPlayer({ src, isPlaying }) {
@@ -455,17 +463,17 @@ function VideoPlayer({ src, isPlaying }) {
}, [isPlaying, ref]);
```
-The [`set` functions](/reference/react/useState#setstate) returned by `useState` also have stable identity, so you will often see them omitted from the dependencies too. If the linter lets you omit a dependency without errors, it is safe to do.
+`useState`:n palauttamilla [`set` funktioilla](/reference/react/useState#setstate) on myös vakaa identiteetti, joten näet usein että se jätetään riippuvuustaulukosta pois. Jos linter sallii riippuvuuden jättämisen pois ilman virheitä, se on turvallista tehdä.
-Omitting always-stable dependencies only works when the linter can "see" that the object is stable. For example, if `ref` was passed from a parent component, you would have to specify it in the dependency array. However, this is good because you can't know whether the parent component always passes the same ref, or passes one of several refs conditionally. So your Effect _would_ depend on which ref is passed.
+Aina-vakaiden riippuvuuksien jättäminen pois toimii vain kun linter voi "nähdä", että olio on vakaa. Esimerkiksi, jos `ref` välitetään yläkomponentilta, sinun täytyy määritellä se riippuvuustaulukkoon. Kuitenkin, tämä on hyvä tehdä koska et voi tietää, että yläkomponentti välittää aina saman refin, tai välittää yhden useista refeistä ehdollisesti. Joten Effectisi _riippuisi_ siitä, mikä ref välitetään.
-### Step 3: Add cleanup if needed {/*step-3-add-cleanup-if-needed*/}
+### 3. Vaihe: Lisää puhdistus tarvittaessa {/*step-3-add-cleanup-if-needed*/}
-Consider a different example. You're writing a `ChatRoom` component that needs to connect to the chat server when it appears. You are given a `createConnection()` API that returns an object with `connect()` and `disconnect()` methods. How do you keep the component connected while it is displayed to the user?
+Harkitse hieman erilaista esimerkkiä. Kirjoitat `ChatRoom` komponenttia, jonka tarvitsee yhdistää chat palvelimeen kun se ilmestyy. Sinulle annetaan `createConnection()` API joka palauttaa olion, jossa on `connect()` ja `disconnect()` metodit. Kuinka pidät komponentin yhdistettynä kun se näytetään käyttäjälle?
-Start by writing the Effect logic:
+Aloita kirjoittamalla Effectin logiikka:
```js
useEffect(() => {
@@ -474,7 +482,7 @@ useEffect(() => {
});
```
-It would be slow to connect to the chat after every re-render, so you add the dependency array:
+Olisi hidasta yhdistää chat -palvelimeen joka renderöinnin jälkeen, joten lisäät riippuvuustaulukon:
```js {4}
useEffect(() => {
@@ -483,9 +491,9 @@ useEffect(() => {
}, []);
```
-**The code inside the Effect does not use any props or state, so your dependency array is `[]` (empty). This tells React to only run this code when the component "mounts", i.e. appears on the screen for the first time.**
+**Effectin sisällä oleva koodi ei käytä yhtäkään propsia tai tilamuuttujaa, joten riippuvuustaulukkosi on `[]` (tyhjä). Tämä kertoo Reactille että suorittaa tämän koodin vain kun komponentti "mounttaa", eli näkyy ensimmäistä kertaa näytöllä.**
-Let's try running this code:
+Kokeillaan koodin suorittamista:
@@ -504,7 +512,7 @@ export default function ChatRoom() {
```js chat.js
export function createConnection() {
- // A real implementation would actually connect to the server
+ // Oikea toteutus yhdistäisi todellisuudessa palvelimeen
return {
connect() {
console.log('✅ Connecting...');
@@ -522,15 +530,13 @@ input { display: block; margin-bottom: 20px; }
-This Effect only runs on mount, so you might expect `"✅ Connecting..."` to be printed once in the console. **However, if you check the console, `"✅ Connecting..."` gets printed twice. Why does it happen?**
+Tämä Effecti suoritetaan vain mountissa, joten voit odottaa että `"✅ Connecting..."` tulostuu kerran konsoliin. **Kuitenkin, jos tarkistat konsolin, `"✅ Connecting..."` tulostuu kaksi kertaa. Miksi se tapahtuu?**
-Imagine the `ChatRoom` component is a part of a larger app with many different screens. The user starts their journey on the `ChatRoom` page. The component mounts and calls `connection.connect()`. Then imagine the user navigates to another screen--for example, to the Settings page. The `ChatRoom` component unmounts. Finally, the user clicks Back and `ChatRoom` mounts again. This would set up a second connection--but the first connection was never destroyed! As the user navigates across the app, the connections would keep piling up.
+Kuvittele, että `ChatRoom` komponentti on osa isompaa sovellusta, jossa on useita eri näyttöjä. Käyttäjä aloittaa matkansa `ChatRoom` sivulta. Komponentti mounttaa ja kutsuu `connection.connect()`. Sitten kuvittele, että käyttäjä navigoi toiselle näytölle--esimerkiksi asetussivulle. `ChatRoom` komponentti unmounttaa. Lopuksi, käyttäjä painaa Takaisin -nappia ja `ChatRoom` mounttaa uudelleen. Tämä yhdistäisi toiseen kertaan--mutta ensimmäistä yhdistämistä ei koskaan tuhottu! Kun käyttäjä navigoi sovelluksen läpi, yhteydet kasaantuisivat.
-Bugs like this are easy to miss without extensive manual testing. To help you spot them quickly, in development React remounts every component once immediately after its initial mount.
+Tämän kaltaiset bugit voivat helposti jäädä huomiotta ilman raskasta manuaalista testaamista. Helpottaaksesi näiden löytämistä, React kehitysvaiheessa remounttaa jokaisen komponentin kerran heti mountin jälkeen. **Nähdessäsi `"✅ Connecting..."` tulostuksen kahdesti, huomaat helposti ongelman: koodisi ei sulje yhteyttä kun komponentti unmounttaa.**
-Seeing the `"✅ Connecting..."` log twice helps you notice the real issue: your code doesn't close the connection when the component unmounts.
-
-To fix the issue, return a *cleanup function* from your Effect:
+Korjataksesi ongelman, palauta *siivousfunktio* Effectistäsi:
```js {4-6}
useEffect(() => {
@@ -542,7 +548,7 @@ To fix the issue, return a *cleanup function* from your Effect:
}, []);
```
-React will call your cleanup function each time before the Effect runs again, and one final time when the component unmounts (gets removed). Let's see what happens when the cleanup function is implemented:
+React kutsuu siivousfunktiotasi joka kerta ennen kuin Effectia suoritetaan uudelleen, ja kerran kun komponentti unmounttaa (poistetaan). Kokeillaan mitä tapahtuu kun siivousfunktio on toteutettu:
@@ -562,7 +568,7 @@ export default function ChatRoom() {
```js chat.js
export function createConnection() {
- // A real implementation would actually connect to the server
+ // Oikea toteutus yhdistäisi todellisuudessa palvelimeen
return {
connect() {
console.log('✅ Connecting...');
@@ -580,27 +586,27 @@ input { display: block; margin-bottom: 20px; }
-Now you get three console logs in development:
+Nyt saat kolme tulostusta konsoliin kehitysvaiheessa:
1. `"✅ Connecting..."`
2. `"❌ Disconnected."`
3. `"✅ Connecting..."`
-**This is the correct behavior in development.** By remounting your component, React verifies that navigating away and back would not break your code. Disconnecting and then connecting again is exactly what should happen! When you implement the cleanup well, there should be no user-visible difference between running the Effect once vs running it, cleaning it up, and running it again. There's an extra connect/disconnect call pair because React is probing your code for bugs in development. This is normal--don't try to make it go away!
+**Tämä on kehitysvaiheen oikea käyttäytyminen.** Remounttaamalla komponenttisi, React varmistaa että navigointi pois ja takaisin ei riko koodiasi. Yhdistäminen ja sitten katkaiseminen on juuri se mitä pitäisi tapahtua! Kun toteutat siivouksen hyvin, käyttäjälle ei pitäisi olla näkyvissä eroa suorittamalla Effectiä kerran vs suorittamalla se, siivoamalla se ja suorittamalla se uudelleen. Ylimääräinen yhdistys/katkaisu pari on olemassa kehitysvaiheessa, koska React tutkii koodiasi virheiden löytämiseksi. Tämä on normaalia ja sinun ei tulisi yrittää saada sitä pois.
-**In production, you would only see `"✅ Connecting..."` printed once.** Remounting components only happens in development to help you find Effects that need cleanup. You can turn off [Strict Mode](/reference/react/StrictMode) to opt out of the development behavior, but we recommend keeping it on. This lets you find many bugs like the one above.
+**Tuotannossa, näkisit ainoastaan `"✅ Connecting..."` tulostuksen kerran.** Remounttaaminen tapahtuu vain kehitysvaiheessa auttaaksesi sinua löytämään Effectit, joissa on siivousfunktio. Voit kytkeä [Strict Mode:n](/reference/react/Strict-mode) pois päältä, jotta saat kehitysvaiheen toiminnon pois käytöstä, mutta suosittelemme että pidät sen päällä. Tämä auttaa sinua löytämään monia bugeja kuten yllä.
-## How to handle the Effect firing twice in development? {/*how-to-handle-the-effect-firing-twice-in-development*/}
+## Miten käsittelet kahdesti toistuvan Effectin kehitysvaiheessa? {/*how-to-handle-the-effect-firing-twice-in-development*/}
-React intentionally remounts your components in development to find bugs like in the last example. **The right question isn't "how to run an Effect once", but "how to fix my Effect so that it works after remounting".**
+React tarkoituksella remounttaa komponenttisi kehitysvaiheessa auttaaksesi sinua löytämään bugeja kuten edellisessä esimerkissä. **Oikea kysymys ei ole "miten suoritan Effectin kerran", vaan "miten korjaan Effectini niin että se toimii remounttauksen jälkeen".**
-Usually, the answer is to implement the cleanup function. The cleanup function should stop or undo whatever the Effect was doing. The rule of thumb is that the user shouldn't be able to distinguish between the Effect running once (as in production) and a _setup → cleanup → setup_ sequence (as you'd see in development).
+Useiten vastaus on toteuttaa siivousfunktio. Siivousfunktion pitäisi pysäyttää tai peruuttaa se mitä Effect oli tekemässä. Yleinen sääntö on että käyttäjän ei pitäisi pystyä erottamaan Effectin suorittamista kerran (tuotannossa) ja _setup → cleanup → setup_ sekvenssistä (mitä näet kehitysvaiheessa).
-Most of the Effects you'll write will fit into one of the common patterns below.
+Useimmat Effectit jotka kirjoitat sopivat yhteen alla olevista yleisistä kuvioista.
-### Controlling non-React widgets {/*controlling-non-react-widgets*/}
+### Ei-React komponenttien ohjaaminen {/*controlling-non-react-widgets*/}
-Sometimes you need to add UI widgets that aren't written to React. For example, let's say you're adding a map component to your page. It has a `setZoomLevel()` method, and you'd like to keep the zoom level in sync with a `zoomLevel` state variable in your React code. Your Effect would look similar to this:
+Joskus tarvitset UI pienoisohjelmia, jotka eivät ole kirjoitettu Reactiin. Esimerkiksi, sanotaan että lisäät kartta-komponentin sivullesi. Sillä on `setZoomLevel()` metodi, ja haluat pitää zoom tason synkronoituna `zoomLevel` tilamuuttujan kanssa React koodissasi. Effectisi näyttäisi tältä:
```js
useEffect(() => {
@@ -609,9 +615,9 @@ useEffect(() => {
}, [zoomLevel]);
```
-Note that there is no cleanup needed in this case. In development, React will call the Effect twice, but this is not a problem because calling `setZoomLevel` twice with the same value does not do anything. It may be slightly slower, but this doesn't matter because it won't remount needlessly in production.
+Huomaa, että tässä tilanteessa siivousta ei tarvita. Kehitysvaiheessa React kutsuu Effectia kahdesti, mutta tässä se ei ole ongelma, koska `setZoomLevel`:n kutsuminen kahdesti samalla arvolla ei tee mitään. Se saattaa olla hieman hitaampaa, mutta tämä ei ole ongelma koska remounttaus tapahtuu kehitysvaiheessa eikä tuotannossa.
-Some APIs may not allow you to call them twice in a row. For example, the [`showModal`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal) method of the built-in [``](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement) element throws if you call it twice. Implement the cleanup function and make it close the dialog:
+Jotkin API:t eivät salli kutsua niitä kahdesti peräkkäin. Esimerkiksi, sisäänrakennetun [``](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement) elementin [`showModal`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal) metodi heittää virheen jos kutsut sitä kahdesti peräkkäin. Toteuta siivousfunktio, joka sulkee dialogin:
```js {4}
useEffect(() => {
@@ -621,11 +627,11 @@ useEffect(() => {
}, []);
```
-In development, your Effect will call `showModal()`, then immediately `close()`, and then `showModal()` again. This has the same user-visible behavior as calling `showModal()` once, as you would see in production.
+Kehitysvaiheessa Effectisi kutsuu `showModal()` metodia, jonka perään heti `close()`, ja sitten `showModal()` metodia uudelleen. Tämä on käyttäjälle sama kuin jos kutsuisit `showModal()` metodia vain kerran, kuten näet tuotannossa.
-### Subscribing to events {/*subscribing-to-events*/}
+### Tapahtumien tilaaminen {/*subscribing-to-events*/}
-If your Effect subscribes to something, the cleanup function should unsubscribe:
+Jos Effectisi tilaavat jotain, siivousfunktiosi pitäisi purkaa tilaus:
```js {6}
useEffect(() => {
@@ -637,27 +643,27 @@ useEffect(() => {
}, []);
```
-In development, your Effect will call `addEventListener()`, then immediately `removeEventListener()`, and then `addEventListener()` again with the same handler. So there would be only one active subscription at a time. This has the same user-visible behavior as calling `addEventListener()` once, as in production.
+Kehitysvaiheessa Effectisi kutsuu `addEventListener()` metodia, jonka perään heti `removeEventListener()` metodia, ja sitten `addEventListener()` metodia uudelleen samalla käsittelijällä. Joten aina on vain yksi aktiivinen tilaus kerrallaan. Tämä on käyttäjälle sama kuin jos kutsuisit `addEventListener()` metodia vain kerran, kuten näet tuotannossa.
-### Triggering animations {/*triggering-animations*/}
+### Animaatioiden käynnistäminen {/*triggering-animations*/}
-If your Effect animates something in, the cleanup function should reset the animation to the initial values:
+Jos Effectisi animoi jotain, siivousfunktiosi pitäisi palauttaa animaatio alkuperäiseen tilaan:
```js {4-6}
useEffect(() => {
const node = ref.current;
- node.style.opacity = 1; // Trigger the animation
+ node.style.opacity = 1; // Käynnistä animaatio
return () => {
- node.style.opacity = 0; // Reset to the initial value
+ node.style.opacity = 0; // Palauta oletusarvoon
};
}, []);
```
-In development, opacity will be set to `1`, then to `0`, and then to `1` again. This should have the same user-visible behavior as setting it to `1` directly, which is what would happen in production. If you use a third-party animation library with support for tweening, your cleanup function should reset the timeline to its initial state.
+Kehitysvaiheessa läpinäkyvyys asetetaan `1`:een, sitten `0`:aan, ja sitten `1`:een uudelleen. Tämä pitäisi olla käyttäjälle sama kuin jos asettaisit sen suoraan `1`:een, joka olisi mitä tapahtuu tuotannossa. Jos käytät kolmannen osapuolen animaatiokirjastoa joka tukee tweenausta (engl. tweening), siivousfunktion pitäisi palauttaa tweenin aikajana alkuperäiseen tilaan.
-### Fetching data {/*fetching-data*/}
+### Tiedon haku {/*tiedon-haku*/}
-If your Effect fetches something, the cleanup function should either [abort the fetch](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) or ignore its result:
+Jos Effectisi hakee jotain, siivousfunktiosi pitäisi joko [perua haku](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) tai sivuuttaa sen tulos:
```js {2,6,13-15}
useEffect(() => {
@@ -678,11 +684,11 @@ useEffect(() => {
}, [userId]);
```
-You can't "undo" a network request that already happened, but your cleanup function should ensure that the fetch that's _not relevant anymore_ does not keep affecting your application. If the `userId` changes from `'Alice'` to `'Bob'`, cleanup ensures that the `'Alice'` response is ignored even if it arrives after `'Bob'`.
+Et voi "peruuttaa" verkkopyyntöä joka on jo tapahtunut, mutta siivousfunktiosi pitäisi varmistaa että pyyntö joka ei ole enää tarpeellinen ei vaikuta sovellukseesi. Jos `userId` muuttuu `'Alice'`:sta `'Bob'`:ksi, siivousfunktio varmistaa että `'Alice'` vastaus jätetään huomiotta vaikka se vastaanotettaisiin `'Bob'`:n vastauksen jälkeen.
-**In development, you will see two fetches in the Network tab.** There is nothing wrong with that. With the approach above, the first Effect will immediately get cleaned up so its copy of the `ignore` variable will be set to `true`. So even though there is an extra request, it won't affect the state thanks to the `if (!ignore)` check.
+**Kehitysvaiheessa, näet kaksi verkkopyyntöä Network välilehdellä.** Tässä ei ole mitään vikaa. Yllä olevan menetelmän mukaan, ensimmäinen Effecti poistetaan välittömästi, joten sen kopio `ignore` muuttujasta asetetaan `true`:ksi. Joten vaikka onkin ylimääräinen pyyntö, se ei vaikuta tilaan kiitos `if (!ignore)` tarkistuksen.
-**In production, there will only be one request.** If the second request in development is bothering you, the best approach is to use a solution that deduplicates requests and caches their responses between components:
+**Tuotannossa tulee tapahtumaan vain yksi pyyntö.** Jos kehitysvaiheessa toinen pyyntö häiritsee sinua, paras tapa on käyttää ratkaisua joka deduplikoi pyynnöt ja asettaa niiden vastaukset välimuistiin komponenttien välillä:
```js
function TodoList() {
@@ -690,50 +696,50 @@ function TodoList() {
// ...
```
-This will not only improve the development experience, but also make your application feel faster. For example, the user pressing the Back button won't have to wait for some data to load again because it will be cached. You can either build such a cache yourself or use one of the many alternatives to manual fetching in Effects.
+Tämä ei vain paranna kehityskokemusta, vaan myös saa sovelluksesi tuntumaan nopeammalta. Esimerkiksi, käyttäjän ei tarvitse odottaa että jotain dataa ladataan uudelleen kun painaa Takaisin -painiketta, koska se on välimuistissa. Voit joko rakentaa tällaisen välimuistin itse tai effecteissa manuaalisen datahaun sijaan käyttää jotain olemassa olevaa vaihtoehtoa.
-#### What are good alternatives to data fetching in Effects? {/*what-are-good-alternatives-to-data-fetching-in-effects*/}
+#### Mitkä ovat hyviä vaihtoehtoja datan hakemiseen effecteissa? {/*what-are-good-alternatives-to-data-fetching-in-effects*/}
-Writing `fetch` calls inside Effects is a [popular way to fetch data](https://www.robinwieruch.de/react-hooks-fetch-data/), especially in fully client-side apps. This is, however, a very manual approach and it has significant downsides:
+`fetch` kutsujen kirjoittaminen Effecteissa on [suosittu tapa hakea dataa](https://www.robinwieruch.de/react-hooks-fetch-data/), erityisesti täysin asiakaspuolen sovelluksissa. Tämä on kuitenkin hyvin manuaalinen tapa ja sillä on merkittäviä haittoja:
-- **Effects don't run on the server.** This means that the initial server-rendered HTML will only include a loading state with no data. The client computer will have to download all JavaScript and render your app only to discover that now it needs to load the data. This is not very efficient.
-- **Fetching directly in Effects makes it easy to create "network waterfalls".** You render the parent component, it fetches some data, renders the child components, and then they start fetching their data. If the network is not very fast, this is significantly slower than fetching all data in parallel.
-- **Fetching directly in Effects usually means you don't preload or cache data.** For example, if the component unmounts and then mounts again, it would have to fetch the data again.
-- **It's not very ergonomic.** There's quite a bit of boilerplate code involved when writing `fetch` calls in a way that doesn't suffer from bugs like [race conditions.](https://maxrozen.com/race-conditions-fetching-data-react-with-useeffect)
+- **Effecteja ei ajeta palvelimella.** Tämä tarkoittaa, että palvelimella renderöity HTML sisältää vain lataus -tilan ilman dataa. Asiakkaan tietokoneen pitää ladata koko JavaScript ja renderöidä sovellus, jotta se huomaa, että nyt sen täytyy ladata dataa. Tämä ei ole erityisen tehokasta.
+- **Hakeminen Effectissa tekee "verkkovesiputouksien" toteuttamisesta helppoa.** Renderöit ylemmän komponentin, se hakee jotain dataa, renderöit lapsikomponentit, ja sitten ne alkavat hakea omaa dataansa. Jos verkkoyhteys ei ole erityisen nopea, tämä on huomattavasti hitaampaa kuin jos kaikki datat haettaisiin yhtäaikaisesti.
+- **Hakeminen suoraan Effecteissa useiten tarkoittaa ettet esilataa tai välimuista dataa.** Esimerkiksi, jos komponentti poistetaan ja sitten liitetään takaisin, se joutuu hakemaan datan uudelleen.
+- **Se ei ole kovin ergonomista.** Pohjakoodia on aika paljon kirjoittaessa `fetch` kutsuja tavalla, joka ei kärsi bugeista kuten [kilpailutilanteista.](https://maxrozen.com/race-conditions-fetching-data-react-with-useeffect)
-This list of downsides is not specific to React. It applies to fetching data on mount with any library. Like with routing, data fetching is not trivial to do well, so we recommend the following approaches:
+Tämä lista huonoista puolista ei koske pelkästään Reactia. Se pätee mihin tahansa kirjastoon kun dataa haetaan mountissa. Kuten reitityksessä, datan hakeminen ei ole helppoa tehdä hyvin, joten suosittelemme seuraavia lähestymistapoja:
-- **If you use a [framework](/learn/start-a-new-react-project#production-grade-react-frameworks), use its built-in data fetching mechanism.** Modern React frameworks have integrated data fetching mechanisms that are efficient and don't suffer from the above pitfalls.
-- **Otherwise, consider using or building a client-side cache.** Popular open source solutions include [React Query](https://tanstack.com/query/latest), [useSWR](https://swr.vercel.app/), and [React Router 6.4+.](https://beta.reactrouter.com/en/main/start/overview) You can build your own solution too, in which case you would use Effects under the hood, but add logic for deduplicating requests, caching responses, and avoiding network waterfalls (by preloading data or hoisting data requirements to routes).
+- **Jos käytät [frameworkia](/learn/start-a-new-react-project#building-with-a-full-featured-framework), käytä sen sisäänrakennettua datan hakemiseen tarkoitettua mekanismia.** Modernit React frameworkit sisältävät tehokkaita datan hakemiseen tarkoitettuja mekanismeja, jotka eivät kärsi yllä mainituista ongelmista.
+- **Muussa tapauksessa, harkitse tai rakenna asiakaspuolen välimuisti.** Suosittuja avoimen lähdekoodin ratkaisuja ovat [React Query](https://tanstack.com/query/latest), [useSWR](https://swr.vercel.app/), ja [React Router 6.4+.](https://beta.reactrouter.com/en/main/start/overview) Voit myös rakentaa oman ratkaisusi, jolloin käytät Effecteja alustana mutta lisäät logiikkaa pyyntöjen deduplikointiin, vastausten välimuistitukseen ja verkkovesiputousten välttämiseen (esilataamalla dataa tai nostamalla datan vaatimukset reiteille).
-You can continue fetching data directly in Effects if neither of these approaches suit you.
+Voit jatkaa datan hakemista suoraan Effecteissa jos nämä lähestymistavat eivät sovi sinulle.
-### Sending analytics {/*sending-analytics*/}
+### Analytiikan lähettäminen {/*sending-analytics*/}
-Consider this code that sends an analytics event on the page visit:
+Harkitse tätä koodia, joka lähettää analytiikkatapahtuman sivun vierailusta:
```js
useEffect(() => {
- logVisit(url); // Sends a POST request
+ logVisit(url); // Lähettää POST pyynnön
}, [url]);
```
-In development, `logVisit` will be called twice for every URL, so you might be tempted to try to fix that. **We recommend keeping this code as is.** Like with earlier examples, there is no *user-visible* behavior difference between running it once and running it twice. From a practical point of view, `logVisit` should not do anything in development because you don't want the logs from the development machines to skew the production metrics. Your component remounts every time you save its file, so it logs extra visits in development anyway.
+Kehitysvaiheessa `logVisit` kutsutaan kahdesti jokaiselle URL:lle, joten saattaa olla houkuttelevaa tämän välttämistä. **Suosittelemme pitämään tämän koodin sellaisenaan.** Kuten aiemmissa esimerkeissä, ei ole *käyttäjän näkökulmasta* havaittavaa eroa siitä, ajetaanko se kerran vai kahdesti. Käytännöllisestä näkökulmasta `logVisit`:n ei tulisi tehdä mitään kehitysvaiheessa, koska et halua, että kehityskoneiden lokit vaikuttavat tuotantotilastoihin. Komponenttisi remounttaa joka kerta kun tallennat sen tiedoston, joten se lähettäisi ylimääräisiä vierailuja kehitysvaiheessa joka tapauksessa.
-**In production, there will be no duplicate visit logs.**
+**Tuotannossa ei ole kaksoiskappaleita vierailulokeista.**
-To debug the analytics events you're sending, you can deploy your app to a staging environment (which runs in production mode) or temporarily opt out of [Strict Mode](/reference/react/StrictMode) and its development-only remounting checks. You may also send analytics from the route change event handlers instead of Effects. For more precise analytics, [intersection observers](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) can help track which components are in the viewport and how long they remain visible.
+Analytiikkatapahtumien debuggauukseen voit joko julkaista sovelluksen testiympäristöön (joka suoritetaan tuotantotilassa) tai väliaikaisesti poistaa käytöstä [Strict Mode](/reference/react/StrictMode):n ja sen kehitysvaiheessa olevat remounttaus-tarkistukset. Voit myös lähettää analytiikkaa reitityksen tapahtumakäsittelijöistä Effectien sijaan. Entistäkin tarkemman analytiikan lähettämiseen voit käyttää [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API):a, jotka auttavat seuraamaan, mitkä komponentit ovat näkyvissä ja kuinka kauan.
-### Not an Effect: Initializing the application {/*not-an-effect-initializing-the-application*/}
+### Ei ole Effect: Sovelluksen alustaminen {/*not-an-effect-initializing-the-application*/}
-Some logic should only run once when the application starts. You can put it outside your components:
+Jokin logiikka tulisi suorittaa vain kerran kun sovellus käynnistyy. Voit laittaa sen komponentin ulkopuolelle:
```js {2-3}
-if (typeof window !== 'undefined') { // Check if we're running in the browser.
+if (typeof window !== 'undefined') { // Tarkista suoritetaanko selaimessa
checkAuthToken();
loadDataFromLocalStorage();
}
@@ -743,37 +749,37 @@ function App() {
}
```
-This guarantees that such logic only runs once after the browser loads the page.
+Tämä takaa, että tällainen logiikka suoritetaan vain kerran selaimen lataamisen jälkeen.
-### Not an Effect: Buying a product {/*not-an-effect-buying-a-product*/}
+### Ei ole Effect: Tuotteen ostaminen {/*not-an-effect-buying-a-product*/}
-Sometimes, even if you write a cleanup function, there's no way to prevent user-visible consequences of running the Effect twice. For example, maybe your Effect sends a POST request like buying a product:
+Joksus, vaikka kirjoittaisit siivousfunktion, ei ole tapaa estää käyttäjälle näkyviä seurauksia Effectin kahdesti suorittamisesta. Esimerkiksi, joskus Effecti voi lähettää POST pyynnön kuten tuotteen ostamisen:
```js {2-3}
useEffect(() => {
- // 🔴 Wrong: This Effect fires twice in development, exposing a problem in the code.
+ // 🔴 Väärin: Tämä Effecti suoritetaan kahdesti tuotannossa, paljastaen ongelman koodissa.
fetch('/api/buy', { method: 'POST' });
}, []);
```
-You wouldn't want to buy the product twice. However, this is also why you shouldn't put this logic in an Effect. What if the user goes to another page and then presses Back? Your Effect would run again. You don't want to buy the product when the user *visits* a page; you want to buy it when the user *clicks* the Buy button.
+Et halua ostaa tuotetta kahdesti. Kuitenkin, tämä on myös syy miksi et halua laittaa tätä logiikkaa Effectiin. Mitä jos käyttäjä menee toiselle sivulle ja tulee takaisin? Effectisi suoritetaan uudelleen. Et halua ostaa tuotetta koska käyttäjä *vieraili* sivulla; haluat ostaa sen kun käyttäjä *painaa* Osta -nappia.
-Buying is not caused by rendering; it's caused by a specific interaction. It should run only when the user presses the button. **Delete the Effect and move your `/api/buy` request into the Buy button event handler:**
+Ostaminen ei aiheutunut renderöinnin takia. Se aiheutuu tietyn vuorovaikutuksen takia. Se suoritetaan vain kerran koska vuorovaikutus (napsautus) tapahtuu vain kerran. **Poista Effecti ja siirrä `/api/buy` pyyntö Osta -painkkeen tapahtumakäsittelijään:**
```js {2-3}
function handleClick() {
- // ✅ Buying is an event because it is caused by a particular interaction.
+ // ✅ Ostaminen on tapahtuma, koska se aiheutuu tietyn vuorovaikutuksen seurauksena.
fetch('/api/buy', { method: 'POST' });
}
```
-**This illustrates that if remounting breaks the logic of your application, this usually uncovers existing bugs.** From the user's perspective, visiting a page shouldn't be different from visiting it, clicking a link, and pressing Back. React verifies that your components abide by this principle by remounting them once in development.
+**Tämä osoittaa, että jos remounttaus rikkoo sovelluksen logiikkaa, tämä usein paljastaa olemassa olevia virheitä.** Käyttäjän näkökulmasta, sivulla vierailu ei pitäisi olla sen erilaisempaa kuin vierailu, linkin napsautus ja sitten Takaisin -painikkeen napsauttaminen. React varmistaa, että komponenttisi eivät riko tätä periaatetta kehitysvaiheessa remounttaamalla niitä kerran.
-## Putting it all together {/*putting-it-all-together*/}
+## Laitetaan kaikki yhteen {/*putting-it-all-together*/}
-This playground can help you "get a feel" for how Effects work in practice.
+Tämä hiekkalaatikko voi auttaa "saamaan tunteen" siitä, miten Effectit toimivat käytännössä.
-This example uses [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) to schedule a console log with the input text to appear three seconds after the Effect runs. The cleanup function cancels the pending timeout. Start by pressing "Mount the component":
+Tämä esimerkki käyttää [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) funktiota aikatauluttaakseen konsolilokiin syötetyn tekstin ilmestyvän kolmen sekunnin kuluttua Effectin suorittamisen jälkeen. Siivoamisfunktio peruuttaa odottavan aikakatkaisun. Aloita painamalla "Mount the component":
@@ -827,21 +833,21 @@ export default function App() {
-You will see three logs at first: `Schedule "a" log`, `Cancel "a" log`, and `Schedule "a" log` again. Three second later there will also be a log saying `a`. As you learned earlier, the extra schedule/cancel pair is because React remounts the component once in development to verify that you've implemented cleanup well.
+Näet aluksi kolme eri lokia: `Schedule "a" log`, `Cancel "a" log`, ja `Schedule "a" log` uudelleen. Kolme sekuntia myöhemmin lokiin ilmestyy viesti `a`. Kuten opit aiemmin tällä sivulla, ylimääräinen schedule/cancel pari tapahtuu koska **React remounttaa komponentin kerran kehitysvaiheessa varmistaakseen, että olet toteuttanut siivouksen hyvin.**
-Now edit the input to say `abc`. If you do it fast enough, you'll see `Schedule "ab" log` immediately followed by `Cancel "ab" log` and `Schedule "abc" log`. **React always cleans up the previous render's Effect before the next render's Effect.** This is why even if you type into the input fast, there is at most one timeout scheduled at a time. Edit the input a few times and watch the console to get a feel for how Effects get cleaned up.
+Nyt muokkaa syöttölaatikon arvoksi `abc`. Jos teet sen tarpeeksi nopeasti, näet `Schedule "ab" log` viestin, jonka jälkeen `Cancel "ab" log` ja `Schedule "abc" log`. **React siivoaa aina edellisen renderöinnin Effectin ennen seuraavan renderöinnin Effectiä.** Tämä on syy miksi vaikka kirjoittaisit syöttölaatikkoon nopeasti, aikakatkaisuja on aina enintään yksi kerrallaan. Muokkaa syöttölaatikkoa muutaman kerran ja katso konsolia saadaksesi käsityksen siitä, miten Effectit siivotaan.
-Type something into the input and then immediately press "Unmount the component". Notice how unmounting cleans up the last render's Effect. Here, it clears the last timeout before it has a chance to fire.
+Kirjoita jotain syöttölaatikkoon ja heti perään paina "Unmount the component". **Huomaa kuinka unmounttaus siivoaa viimeisen renderöinnin Effectin.** Tässä esimerkissä se tyhjentää viimeisen aikakatkaisun ennen kuin se ehtii käynnistyä.
-Finally, edit the component above and comment out the cleanup function so that the timeouts don't get cancelled. Try typing `abcde` fast. What do you expect to happen in three seconds? Will `console.log(text)` inside the timeout print the *latest* `text` and produce five `abcde` logs? Give it a try to check your intuition!
+Lopuksi, muokkaa yllä olevaa komponenttia ja **kommentoi siivousfunktio**, jotta ajastuksia ei peruuteta. Kokeile kirjoittaa `abcde` nopeasti. Mitä odotat tapahtuvan kolmen sekuntin kuluttua? Tulisiko `console.log(text)` aikakatkaisussa tulostamaan *viimeisimmän* `text`:n ja tuottamaan viisi `abcde` lokia? Kokeile tarkistaaksesi intuitiosi!
-Three seconds later, you should see a sequence of logs (`a`, `ab`, `abc`, `abcd`, and `abcde`) rather than five `abcde` logs. **Each Effect "captures" the `text` value from its corresponding render.** It doesn't matter that the `text` state changed: an Effect from the render with `text = 'ab'` will always see `'ab'`. In other words, Effects from each render are isolated from each other. If you're curious how this works, you can read about [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures).
+Kolmen sekuntin jälkeen lokeissa tulisi näkyä (`a`, `ab`, `abc`, `abcd`, ja `abcde`) viiden `abcde` lokin sijaan. **Kukin Effecti nappaa `text`:n arvon vastaavasta renderöinnistä.** Se ei ole väliä, että `text` tila muuttui: Effecti renderöinnistä `text = 'ab'` näkee aina `'ab'`. Toisin sanottuna, Effectit jokaisesta renderöinnistä ovat toisistaan erillisiä. Jos olet kiinnostunut siitä, miten tämä toimii, voit lukea [closureista](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures).
-#### Each render has its own Effects {/*each-render-has-its-own-effects*/}
+#### Kullakin renderillä on sen omat Effectit {/*each-render-has-its-own-effects*/}
-You can think of `useEffect` as "attaching" a piece of behavior to the render output. Consider this Effect:
+Voit ajatella `useEffect`:ia "liittävän" palan toiminnallisuutta osana renderöinnin tulosta. Harkitse tätä Effectiä:
```js
export default function ChatRoom({ roomId }) {
@@ -855,119 +861,119 @@ export default function ChatRoom({ roomId }) {
}
```
-Let's see what exactly happens as the user navigates around the app.
+Katsotaan mitä oikeasti tapahtuu kun käyttäjä liikkuu sovelluksessa.
-#### Initial render {/*initial-render*/}
+#### Alustava renderöinti {/*initial-render*/}
-The user visits ` `. Let's [mentally substitute](/learn/state-as-a-snapshot#rendering-takes-a-snapshot-in-time) `roomId` with `'general'`:
+Käyttäjä vierailee ` `. Katsotaan [mielikuvitustilassa](/learn/state-as-a-snapshot#rendering-takes-a-snapshot-in-time) `roomId` arvoksi `'general'`:
```js
- // JSX for the first render (roomId = "general")
+ // JSX ensimäisellä renderöinnillä (roomId = "general")
return Welcome to general! ;
```
-**The Effect is *also* a part of the rendering output.** The first render's Effect becomes:
+**Effecti on *myös* osa renderöinnin tulosta.** Ensimmäisen renderöinnin Effecti muuttuu:
```js
- // Effect for the first render (roomId = "general")
+ // Effecti ensimäisellä renderöinnillä (roomId = "general")
() => {
const connection = createConnection('general');
connection.connect();
return () => connection.disconnect();
},
- // Dependencies for the first render (roomId = "general")
+ // Riippuvuudet ensimäisellä renderöinnillä (roomId = "general")
['general']
```
-React runs this Effect, which connects to the `'general'` chat room.
+React suorittaa tämän Effectin, joka yhdistää `'general'` keskusteluhuoneeseen.
-#### Re-render with same dependencies {/*re-render-with-same-dependencies*/}
+#### Uudelleen renderöinti samoilla riippuvuuksilla {/*re-render-with-same-dependencies*/}
-Let's say ` ` re-renders. The JSX output is the same:
+Sanotaan, että ` ` renderöidään uudelleen. JSX tuloste pysyy samana:
```js
- // JSX for the second render (roomId = "general")
+ // JSX toisella renderöinnillä (roomId = "general")
return Welcome to general! ;
```
-React sees that the rendering output has not changed, so it doesn't update the DOM.
+React näkee, että renderöinnin tuloste ei ole muuttunut, joten se ei päivitä DOM:ia.
-The Effect from the second render looks like this:
+Effecti toiselle renderöinnille näyttää tältä:
```js
- // Effect for the second render (roomId = "general")
+ // Effecti toisella renderöinnillä (roomId = "general")
() => {
const connection = createConnection('general');
connection.connect();
return () => connection.disconnect();
},
- // Dependencies for the second render (roomId = "general")
+ // Riippuvuudet toisella renderöinnillä (roomId = "general")
['general']
```
-React compares `['general']` from the second render with `['general']` from the first render. **Because all dependencies are the same, React *ignores* the Effect from the second render.** It never gets called.
+React vertaa `['general']`:a toiselta renderöinniltä ensimmäisen renderöinnin `['general']` kanssa. **Koska kaikki riippuvuudet ovat samat, React *jättää huomiotta* toisen renderöinnin Effectin.** Sitä ei koskaan kutsuta.
-#### Re-render with different dependencies {/*re-render-with-different-dependencies*/}
+#### Uudelleen renderöinti eri riippuvuuksilla {/*re-render-with-different-dependencies*/}
-Then, the user visits ` `. This time, the component returns different JSX:
+Sitten, käyttäjä vierailee ` `. Tällä kertaa komponentti palauttaa eri JSX:ää:
```js
- // JSX for the third render (roomId = "travel")
+ // JSX kolmannella renderöinnillä (roomId = "travel")
return Welcome to travel! ;
```
-React updates the DOM to change `"Welcome to general"` into `"Welcome to travel"`.
+React päivittää DOM:in muuttamalla `"Welcome to general"` lukemaan `"Welcome to travel"`.
-The Effect from the third render looks like this:
+Effecti kolmannelle renderöinnille näyttää tältä:
```js
- // Effect for the third render (roomId = "travel")
+ // Effecti kolmannella renderöinnillä (roomId = "travel")
() => {
const connection = createConnection('travel');
connection.connect();
return () => connection.disconnect();
},
- // Dependencies for the third render (roomId = "travel")
+ // Riippuvuudet kolmannella renderöinnillä (roomId = "travel")
['travel']
```
-React compares `['travel']` from the third render with `['general']` from the second render. One dependency is different: `Object.is('travel', 'general')` is `false`. The Effect can't be skipped.
+React vertaa `['travel']`:ia kolmannelta renderöinniltä toiselta renderöinnin `['general']` kanssa. Yksi riippuvuus on erilainen: `Object.is('travel', 'general')` on `false`. Effectiä ei voi jättää huomiotta.
-**Before React can apply the Effect from the third render, it needs to clean up the last Effect that _did_ run.** The second render's Effect was skipped, so React needs to clean up the first render's Effect. If you scroll up to the first render, you'll see that its cleanup calls `disconnect()` on the connection that was created with `createConnection('general')`. This disconnects the app from the `'general'` chat room.
+**Ennen kuin React voi ottaa käyttöön kolmannen renderöinnin Effectin, sen täytyy siivota viimeisin Effecti joka _suoritettiin_.** Toisen renderöinnin Effecti ohitettiin, joten Reactin täytyy siivota ensimmäisen renderöinnin Effecti. Jos selaat ylös ensimmäiseen renderöintiin, näet että sen siivous kutsuu `createConnection('general')`:lla luodun yhteyden `disconnect()` metodia. Tämä irroittaa sovelluksen `'general'` keskusteluhuoneesta.
-After that, React runs the third render's Effect. It connects to the `'travel'` chat room.
+Sen jälkeen React suorittaa kolmannen renderöinnin Effectin. Se yhdistää sovelluksen `'travel'` keskusteluhuoneeseen.
#### Unmount {/*unmount*/}
-Finally, let's say the user navigates away, and the `ChatRoom` component unmounts. React runs the last Effect's cleanup function. The last Effect was from the third render. The third render's cleanup destroys the `createConnection('travel')` connection. So the app disconnects from the `'travel'` room.
+Lopuksi, sanotaan, että käyttäjä siirtyy pois ja `ChatRoom` komponentti unmounttaa. React suorittaa viimeisen Effectin siivousfunktion. Viimeinen Effecti oli kolmannen renderöinnin. Kolmannen renderöinnin siivousfunktio tuhoaa `createConnection('travel')` yhteyden. Joten sovellus irroittaa itsensä `'travel'` keskusteluhuoneesta.
-#### Development-only behaviors {/*development-only-behaviors*/}
+#### Kehitysvaiheen käyttäytymiset {/*development-only-behaviors*/}
-When [Strict Mode](/reference/react/StrictMode) is on, React remounts every component once after mount (state and DOM are preserved). This [helps you find Effects that need cleanup](#step-3-add-cleanup-if-needed) and exposes bugs like race conditions early. Additionally, React will remount the Effects whenever you save a file in development. Both of these behaviors are development-only.
+Kun [Strict Mode](/reference/react/StrictMode) on käytössä, React remounttaa jokaisen komponentin kerran mountin jälkeen (tila ja DOM säilytetään). Tämä [helpottaa löytämään Effecteja jotka tarvitsevat siivousfunktiota](#step-3-add-cleanup-if-needed) ja paljastaa bugeja kuten kilpailutilanteita (engl. race conditions). Lisäksi, React remounttaa Effectit joka kerta kun tallennat tiedoston kehitysvaiheessa. Molemmat näistä käyttäytymisistä tapahtuu ainoastaan kehitysvaiheessa.
-- Unlike events, Effects are caused by rendering itself rather than a particular interaction.
-- Effects let you synchronize a component with some external system (third-party API, network, etc).
-- By default, Effects run after every render (including the initial one).
-- React will skip the Effect if all of its dependencies have the same values as during the last render.
-- You can't "choose" your dependencies. They are determined by the code inside the Effect.
-- Empty dependency array (`[]`) corresponds to the component "mounting", i.e. being added to the screen.
-- In Strict Mode, React mounts components twice (in development only!) to stress-test your Effects.
-- If your Effect breaks because of remounting, you need to implement a cleanup function.
-- React will call your cleanup function before the Effect runs next time, and during the unmount.
+- Toisin kuin tapahtumat, Effectit aiheutuvat renderöinnin seurauksena tietyn vuorovaikutuksen sijaan.
+- Effectien avulla voit synkronoida komponentin jonkin ulkoisen järjestelmän kanss (kolmannen osapuolen API:n, verkon, jne.).
+- Oletuksena, Effectit suoritetaan jokaisen renderöinnin jälkeen (mukaan lukien ensimmäinen renderöinti).
+- React ohittaa Effectin jos kaikki sen riippuvuudet ovat samat kuin viimeisellä renderöinnillä.
+- Et voi "valita" riippuvuuksiasi. Ne määräytyvät Effectin sisällä olevan koodin mukaan.
+- Tyhjä riippuvuustaulukko (`[]`) vastaa komponentin "mounttaamista", eli sitä kun komponentti lisätään näytölle.
+- Kun Strict Mode on käytössä, React mounttaa komponentit kaksi kertaa (vain kehitysvaiheessa!) stressitestataksesi Effecteja.
+- Jos Effecti rikkoutuu remountin takia, sinun täytyy toteuttaa siivousfunktio.
+- React kutsuu siivousfunktiota ennen kuin Effectiasi suoritetaan seuraavan kerran, ja unmountin yhteydessä.
-#### Focus a field on mount {/*focus-a-field-on-mount*/}
+#### Kohdenna kenttään mountattaessa {/*focus-a-field-on-mount*/}
-In this example, the form renders a ` ` component.
+Tässä esimerkissä, lomake renderöi ` ` komponentin.
-Use the input's [`focus()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) method to make `MyInput` automatically focus when it appears on the screen. There is already a commented out implementation, but it doesn't quite work. Figure out why it doesn't work, and fix it. (If you're familiar with the `autoFocus` attribute, pretend that it does not exist: we are reimplementing the same functionality from scratch.)
+Käytä inputin [`focus()`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) metodia, jotta `MyInput` komponentti automaattisesti kohdentuu kun se ilmestyy näytölle. Alhaalla on jo kommentoitu toteutus, mutta se ei toimi täysin. Selvitä miksi se ei toimi ja korjaa se. (Jos olet tutustunut `autoFocus` attribuuttiin, kuvittele, että sitä ei ole olemassa: me toteutamme saman toiminnallisuuden alusta alkaen.)
@@ -977,7 +983,7 @@ import { useEffect, useRef } from 'react';
export default function MyInput({ value, onChange }) {
const ref = useRef(null);
- // TODO: This doesn't quite work. Fix it.
+ // TODO: Tämä ei ihan toimi. Korjaa se.
// ref.current.focus()
return (
@@ -1043,15 +1049,15 @@ body {
-To verify that your solution works, press "Show form" and verify that the input receives focus (becomes highlighted and the cursor is placed inside). Press "Hide form" and "Show form" again. Verify the input is highlighted again.
+Tarkistaaksesi, että ratkaisusi toimii, paina "Show form" ja tarkista, että kenttä kohdentuu (se muuttuu korostetuksi ja kursori asettuu siihen). Paina "Hide form" ja "Show form" uudelleen. Tarkista, että kenttä on korostettu uudelleen.
-`MyInput` should only focus _on mount_ rather than after every render. To verify that the behavior is right, press "Show form" and then repeatedly press the "Make it uppercase" checkbox. Clicking the checkbox should _not_ focus the input above it.
+`MyInput` pitäisi kohdentua _mounttauksen yhteydessä_ eikä jokaisen renderöinnin jälkeen. Varmistaaksesi, että toiminnallisuus on oikein, paina "Show form":ia ja sitten paina toistuvasti "Make it uppercase" valintaruutua. Valintaruudun klikkaaminen ei pitäisi kohdentaa kenttää yllä.
-Calling `ref.current.focus()` during render is wrong because it is a *side effect*. Side effects should either be placed inside an event handler or be declared with `useEffect`. In this case, the side effect is _caused_ by the component appearing rather than by any specific interaction, so it makes sense to put it in an Effect.
+`ref.current.focus()` kutsuminen renderöinnin aikana on väärin, koska se on *sivuvaikutus*. Sivuvaikutukset pitäisi sijoittaa tapahtumankäsittelijöihin tai määritellä `useEffect`:n avulla. Tässä tapauksessa sivuvaikutus on *aiheutettu* komponentin ilmestymisestä, eikä mistään tietystä vuorovaikutuksesta, joten on järkevää sijoittaa se Effectiin.
-To fix the mistake, wrap the `ref.current.focus()` call into an Effect declaration. Then, to ensure that this Effect runs only on mount rather than after every render, add the empty `[]` dependencies to it.
+Korjataksesi virheen, sijoita `ref.current.focus()` kutsu Effectin määrittelyyn. Sitten, varmistaaksesi, että tämä Effect suoritetaan vain mounttauksen yhteydessä eikä jokaisen renderöinnin jälkeen, lisää siihen tyhjä `[]` riippuvuustaulukko.
@@ -1129,13 +1135,13 @@ body {
-#### Focus a field conditionally {/*focus-a-field-conditionally*/}
+#### Kohdenna kenttä ehdollisesti {/*focus-a-field-conditionally*/}
-This form renders two ` ` components.
+Tämä lomake renderöi kaksi ` ` -komponenttia.
-Press "Show form" and notice that the second field automatically gets focused. This is because both of the ` ` components try to focus the field inside. When you call `focus()` for two input fields in a row, the last one always "wins".
+Paina "Show form" ja huomaa, että toinen kenttä kohdentuu automaattisesti. Tämä johtuu siitä, että molemmat ` ` -komponentit yrittävät kohdentaa kentän sisällä. Kun kutsut `focus()` -funktiota kahdelle syöttökentälle peräkkäin, viimeinen aina "voittaa".
-Let's say you want to focus the first field. The first `MyInput` component now receives a boolean `shouldFocus` prop set to `true`. Change the logic so that `focus()` is only called if the `shouldFocus` prop received by `MyInput` is `true`.
+Sanotaan, että haluat kohdentaa ensimmäisen kentän. Nyt ensimmäinen ` ` -komponentti saa boolean-arvon `shouldFocus` -propsin arvolla `true`. Muuta logiikkaa siten, että `focus()` -funktiota kutsutaan vain, jos `MyInput` -komponentti saa `shouldFocus` -propsin arvolla `true`.
@@ -1145,7 +1151,7 @@ import { useEffect, useRef } from 'react';
export default function MyInput({ shouldFocus, value, onChange }) {
const ref = useRef(null);
- // TODO: call focus() only if shouldFocus is true.
+ // TODO: kutsu focus():a vain jos shouldFocus on tosi.
useEffect(() => {
ref.current.focus();
}, []);
@@ -1215,17 +1221,17 @@ body {
-To verify your solution, press "Show form" and "Hide form" repeatedly. When the form appears, only the *first* input should get focused. This is because the parent component renders the first input with `shouldFocus={true}` and the second input with `shouldFocus={false}`. Also check that both inputs still work and you can type into both of them.
+Tarkistaaksesi ratkaisun, paina "Show form" ja "Hide form" toistuvasti. Kun lomake tulee näkyviin, vain *ensimmäisen* kentän tulisi kohdistua. Tämä johtuu siitä, että vanhemman komponentin renderöimä ensimmäinen syöttökenttä saa `shouldFocus={true}` ja toinen syöttökenttä saa `shouldFocus={false}` -propsin. Tarkista myös, että molemmat kentät toimivat edelleen ja voit kirjoittaa molempiin.
-You can't declare an Effect conditionally, but your Effect can include conditional logic.
+Et voi määritellä Effectia ehdollisesti, mutta Effect voi sisältää ehtologiikkaa.
-Put the conditional logic inside the Effect. You will need to specify `shouldFocus` as a dependency because you are using it inside the Effect. (This means that if some input's `shouldFocus` changes from `false` to `true`, it will focus after mount.)
+Laita ehdollinen logiikka Effectin sisään. Sinun täytyy määrittää `shouldFocus` -propsi riippuvuudeksi, koska käytät sitä Effectin sisällä. (Tämä tarkoittaa sitä, että jos jonkin syöttökentän `shouldFocus` -propsi muuttuu arvosta `false` arvoon `true`, se kohdistuu komponentin mounttaamisen jälkeen.)
@@ -1308,15 +1314,15 @@ body {
-#### Fix an interval that fires twice {/*fix-an-interval-that-fires-twice*/}
+#### Korjaa ajastin joka käynnistyy kahdesti {/*fix-an-interval-that-fires-twice*/}
-This `Counter` component displays a counter that should increment every second. On mount, it calls [`setInterval`.](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) This causes `onTick` to run every second. The `onTick` function increments the counter.
+Tämä `Counter` komponentti näyttää laskurin, jonka pitäisi kasvaa joka sekunti. Mounttauksen yhteydessä se kutsuu [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval):ia. Tämä aiheuttaa `onTick` -funktion suorittamisen joka sekunti. `onTick` -funktio kasvattaa laskuria.
-However, instead of incrementing once per second, it increments twice. Why is that? Find the cause of the bug and fix it.
+Kuitenkin, sen sijaan, että se kasvaisi kerran sekunnissa, se kasvaa kahdesti. Miksi? Etsi vian syy ja korjaa se.
-Keep in mind that `setInterval` returns an interval ID, which you can pass to [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval) to stop the interval.
+Pidä mielessä, että `setInterval` palauttaa ajastimen ID:n, jonka voit antaa [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval):lle pysäyttääksesi ajastimen.
@@ -1373,11 +1379,11 @@ body {
-When [Strict Mode](/reference/react/StrictMode) is on (like in the sandboxes on this site), React remounts each component once in development. This causes the interval to be set up twice, and this is why each second the counter increments twice.
+Kun [Strict Mode](/reference/react/StrictMode) on päällä (kuten tällä sivuilla olevissa hiekkalaatikoissa), React remounttaa jokaisen komponentin kerran kehitysvaiheessa. Tämä aiheuttaa ajastimen asettamisen kahdesti, ja tämä on syy siihen, miksi laskuri kasvaa joka sekunti kahdesti.
-However, React's behavior is not the *cause* of the bug: the bug already exists in the code. React's behavior makes the bug more noticeable. The real cause is that this Effect starts a process but doesn't provide a way to clean it up.
+Kuitenkin, Reactin käyttäytyminen ei ole *syy* bugiin: bugi oli jo olemassa koodissa. Reactin käyttäytymienn tekee bugista huomattavamma. Oikea syy on se, että tämä Effect käynnistää prosessin, mutta ei tarjoa tapaa sen siivoamiseen.
-To fix this code, save the interval ID returned by `setInterval`, and implement a cleanup function with [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval):
+Korjataksesi tämän koodin, tallenna `setInterval`:n palauttama ajastimen ID, ja toteuta siivousfunktio [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval):illa:
@@ -1431,13 +1437,13 @@ body {
-In development, React will still remount your component once to verify that you've implemented cleanup well. So there will be a `setInterval` call, immediately followed by `clearInterval`, and `setInterval` again. In production, there will be only one `setInterval` call. The user-visible behavior in both cases is the same: the counter increments once per second.
+Kehitysvaiheessa, React remounttaa komponentin kerran varmistaakseen, että olet toteuttanut siivouksen oikein. Joten siellä on `setInterval` -kutsu, jonka perään heti `clearInterval`, ja `setInterval` uudelleen. Tuotantovaiheessa, siellä on vain yksi `setInterval` -kutsu. Käyttäjälle näkyvä käyttäytyminen molemmissa tapauksissa on sama: laskuri kasvaa kerran sekunnissa.
-#### Fix fetching inside an Effect {/*fix-fetching-inside-an-effect*/}
+#### Korjaa haku Effectin sisällä {/*fix-fetching-inside-an-effect*/}
-This component shows the biography for the selected person. It loads the biography by calling an asynchronous function `fetchBio(person)` on mount and whenever `person` changes. That asynchronous function returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which eventually resolves to a string. When fetching is done, it calls `setBio` to display that string under the select box.
+Tämä komponentti näyttää valitun henkilön biografian. Se lataa biografian kutsumalla asynkronista funktiota `fetchBio(person)` mountissa ja aina kun `person` muuttuu. Tämä asynkroninen funktio palauttaa [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise):n, joka muuttuu merkkijonoksi. Kun haku on valmis, se kutsuu `setBio`:a näyttääkseen merkkijonon valintalaatikon alla.
@@ -1486,31 +1492,30 @@ export async function fetchBio(person) {
+Tässä koodissa on bugi. Aloita valitsemalla "Alice". Sitten valitse "Bob" ja heti sen jälkeen, että valitse "Taylor". Jos teet tämän tarpeeksi nopeasti, huomaat bugin: Taylor on valittuna, mutta kappaleen alla sanotaan "This is Bob's bio."
-There is a bug in this code. Start by selecting "Alice". Then select "Bob" and then immediately after that select "Taylor". If you do this fast enough, you will notice that bug: Taylor is selected, but the paragraph below says "This is Bob's bio."
-
-Why does this happen? Fix the bug inside this Effect.
+Miksi tämä tapahtuu? Korjaa bugi Effectin sisällä.
-If an Effect fetches something asynchronously, it usually needs cleanup.
+Jos Effecti kutsuu jotain asynkronisesti, se tarvitsee siivouksen.
-To trigger the bug, things need to happen in this order:
+Käynnistääksesi bugin, asioiden on tapahduttava tässä järjestyksessä:
-- Selecting `'Bob'` triggers `fetchBio('Bob')`
-- Selecting `'Taylor'` triggers `fetchBio('Taylor')`
-- **Fetching `'Taylor'` completes *before* fetching `'Bob'`**
-- The Effect from the `'Taylor'` render calls `setBio('This is Taylor’s bio')`
-- Fetching `'Bob'` completes
-- The Effect from the `'Bob'` render calls `setBio('This is Bob’s bio')`
+- `'Bob'`:n valita käynnistää `fetchBio('Bob')`
+- `'Taylor'`:n valinta käynnistää `fetchBio('Taylor')`
+- **`'Taylor'` hakeminen suoriutuu loppuun *ennen* `'Bob'`:n hakua**
+- `'Taylor'` renderin Effecti kutsuu `setBio('This is Taylor’s bio')`
+- `'Bob'`:n haku suoriutuu loppuun
+- `'Bob'` renderin Effecti kutsuu `setBio('This is Bob’s bio')`
-This is why you see Bob's bio even though Taylor is selected. Bugs like this are called [race conditions](https://en.wikipedia.org/wiki/Race_condition) because two asynchronous operations are "racing" with each other, and they might arrive in an unexpected order.
+Tämä on syy miksi näet Bobin bion vaikka Taylor on valittuna. Tämän kaltaisia bugeja kutsutaan [kilpailutilanteiksi (engl. race condition)](https://en.wikipedia.org/wiki/Race_condition) koska kaksi asynkronista operaatiota "kilpailevat" toistensa kanssa, ja ne saattavat saapua odottamattomassa järjestyksessä.
-To fix this race condition, add a cleanup function:
+Korjataksesi tämän kilpailutilanteen, lisää siivousfunktio:
@@ -1564,16 +1569,16 @@ export async function fetchBio(person) {
-Each render's Effect has its own `ignore` variable. Initially, the `ignore` variable is set to `false`. However, if an Effect gets cleaned up (such as when you select a different person), its `ignore` variable becomes `true`. So now it doesn't matter in which order the requests complete. Only the last person's Effect will have `ignore` set to `false`, so it will call `setBio(result)`. Past Effects have been cleaned up, so the `if (!ignore)` check will prevent them from calling `setBio`:
+Kunkin renderin Effectilla on sen oma `ignore` muuttuja. Aluksi, `ignore` muuttuja on `false`. Kuitenkin, jos Effecti siivotaan (kuten kun valitset eri henkilön), sen `ignore` muuttuja muuttuu `true`:ksi. Nyt ei ole väliä millä järjestyksellä pyynnöt suoriutuvat. Vain viimeisen henkilön Effectillä on `ignore` muuttuja on asetettu `false`:ksi, joten se kutsuu `setBio(result)`:ia. Menneet Effectit on siivottu, joten `if (!ignore)` tarkistus estää ne kutsumasta `setBio`:
-- Selecting `'Bob'` triggers `fetchBio('Bob')`
-- Selecting `'Taylor'` triggers `fetchBio('Taylor')` **and cleans up the previous (Bob's) Effect**
-- Fetching `'Taylor'` completes *before* fetching `'Bob'`
-- The Effect from the `'Taylor'` render calls `setBio('This is Taylor’s bio')`
-- Fetching `'Bob'` completes
-- The Effect from the `'Bob'` render **does not do anything because its `ignore` flag was set to `true`**
+- `'Bob'`:n valita käynnistää `fetchBio('Bob')`
+- - `'Taylor'`:n valinta käynnistää `fetchBio('Taylor')` **ja siivoaa edellisen (Bobin) Effectin**
+- `'Taylor'` hakeminen suoriutuu loppuun *ennen* `'Bob'`:n hakua
+- `'Taylor'` renderin Effecti kutsuu `setBio('This is Taylor’s bio')`
+- `'Bob'`:n haku suoriutuu loppuun
+- `'Bob'` renderin Effecti kutsuu `setBio('This is Bob’s bio')` **eikä tee mitään koska sen `ignore` muuttuja on asetettu `true`:ksi**
-In addition to ignoring the result of an outdated API call, you can also use [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to cancel the requests that are no longer needed. However, by itself this is not enough to protect against race conditions. More asynchronous steps could be chained after the fetch, so using an explicit flag like `ignore` is the most reliable way to fix this type of problems.
+Vanhentuneen API kutsun tuloksen ohittamisen lisäksi, voit myös käyttää [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController):a peruuttaaksesi pyynnöt jotka eivät ole enää tarpeen. Kuitenkin, tämä ei ole tarpeeksi suojataksesi kilpailutilanteita vastaan. Asynkronisia vaiheita voisi olla ketjutettu pyynnön jälkeen lisää, joten luotettavin tapa korjata tällaisia ongelmia on käyttämällä selkeää ehtoa kuten `ignore` muuttujaa.
diff --git a/src/content/learn/thinking-in-react.md b/src/content/learn/thinking-in-react.md
index 23d4beb3f..38b140f04 100644
--- a/src/content/learn/thinking-in-react.md
+++ b/src/content/learn/thinking-in-react.md
@@ -1,102 +1,119 @@
---
-title: Thinking in React
+title: Ajattelu Reactissa
---
-React can change how you think about the designs you look at and the apps you build. When you build a user interface with React, you will first break it apart into pieces called *components*. Then, you will describe the different visual states for each of your components. Finally, you will connect your components together so that the data flows through them. In this tutorial, we’ll guide you through the thought process of building a searchable product data table with React.
+React saattaa muuttaa miten ajattelet mallien katsomista ja rakentamiasi sovelluksia. Kun rakennat käyttöliittymää Reactilla, rikot sen ensin palasiksi eli *komponenteiksi*. Sitten, kuvailet erilaiset visuaaliset tilat jokaiselle komponentillesi. Lopuksi, yhdistät komponettisi toisiinsa, jotta data liikkuu niiden läpi. Tässä oppaassa käymme läpi haettavan tuotetaulukon luomista Reactin avulla.
-## Start with the mockup {/*start-with-the-mockup*/}
+## Alota mallista {/*start-with-the-mockup*/}
-Imagine that you already have a JSON API and a mockup from a designer.
+Kuvittele, että sinulla on JSON API ja malli designerilta.
-The JSON API returns some data that looks like this:
+JSON API palauttaa dataa, joka näyttää seuraavalta:
```json
[
- { category: "Fruits", price: "$1", stocked: true, name: "Apple" },
- { category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit" },
- { category: "Fruits", price: "$2", stocked: false, name: "Passionfruit" },
- { category: "Vegetables", price: "$2", stocked: true, name: "Spinach" },
- { category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin" },
- { category: "Vegetables", price: "$1", stocked: true, name: "Peas" }
+ {"category": "Fruits", "price": "$1", "stocked": true, "name": "Apple"},
+ {"category": "Fruits", "price": "$1", "stocked": true, "name": "Dragonfruit"},
+ {
+ "category": "Fruits",
+ "price": "$2",
+ "stocked": false,
+ "name": "Passionfruit"
+ },
+ {"category": "Vegetables", "price": "$2", "stocked": true, "name": "Spinach"},
+ {
+ "category": "Vegetables",
+ "price": "$4",
+ "stocked": false,
+ "name": "Pumpkin"
+ },
+ {"category": "Vegetables", "price": "$1", "stocked": true, "name": "Peas"}
]
```
-The mockup looks like this:
+Ja malli tältä:
-
+
-To implement a UI in React, you will usually follow the same five steps.
+Käyttöliittymän toteuttaminen Reactissa seuraa usein viittä samaa vaihetta.
-## Step 1: Break the UI into a component hierarchy {/*step-1-break-the-ui-into-a-component-hierarchy*/}
+## 1. Vaihe: Riko käyttöliittymä komponenttihierarkiaan {/*step-1-break-the-ui-into-a-component-hierarchy*/}
-Start by drawing boxes around every component and subcomponent in the mockup and naming them. If you work with a designer, they may have already named these components in their design tool. Ask them!
+Aloita piirtämällä laatikkoja jokaisen komponentin ja alakomponentin ympärille mallissa ja nimeämällä ne. Jos työskentelet designerin kanssa, he ovat saattaneet jo nimetä nämä komponentit heidän suunnittelutyökalussaan. Tarkista heiltä!
-Depending on your background, you can think about splitting up a design into components in different ways:
+Riippuen taustastasi, voit ajatella mallin jakamista osiin eri tavoin:
-* **Programming**--use the same techniques for deciding if you should create a new function or object. One such technique is the [single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents.
-* **CSS**--consider what you would make class selectors for. (However, components are a bit less granular.)
-* **Design**--consider how you would organize the design's layers.
+- **Ohjelmointi**--käytä samaa tekniikkaa päättääkseen mikäli sinun pitää luoda uusi funktio tai olio. Yksi tekniikka on [single responsibility -periaate](https://en.wikipedia.org/wiki/Single_responsibility_principle), joka tarkoittaa, että komponentin täytyisi tehdä vain yksi asia. Mikäli se päätyy kasvamaan, se pitäisi jakaa pienempiin alakomponentteihin.
+- **CSS**--harkitse mille tekisit luokka-valitsimia. (Kuitenkin, komponentit koostuvat pienistä palasista.)
+- **Design**--harkiste miten järjestäisit mallin eri tasoihin.
-If your JSON is well-structured, you'll often find that it naturally maps to the component structure of your UI. That's because UI and data models often have the same information architecture--that is, the same shape. Separate your UI into components, where each component matches one piece of your data model.
+Huomaat jos JSON:isi on hyvin määriteltyä, se usein mäppäytyy komponentin rakenteeseen käyttöliittymässäsi. Tämä siksi, koska UI ja tietomalleilla usein on sama tietoarkkitehtuuri--eli, sama muoto. Erota käyttöliittymäsi komponenteiksi, jossa jokainen komponentti vastaa yhtä palasta tietomalliasi.
-There are five components on this screen:
+Ruudulla on viisi komponenttia:
-
+
-1. `FilterableProductTable` (grey) contains the entire app.
-2. `SearchBar` (blue) receives the user input.
-3. `ProductTable` (lavender) displays and filters the list according to the user input.
-4. `ProductCategoryRow` (green) displays a heading for each category.
-5. `ProductRow` (yellow) displays a row for each product.
+1. `FilterableProductTable` (harmaa) sisältää koko sovelluksen.
+2. `SearchBar` (sininen) vastaanottaa käyttäjän syötteen.
+3. `ProductTable` (laventeli) näyttää ja suodattaa listan käyttäjän syötteen perusteella.
+4. `ProductCategoryRow` (vihreä) näyttää otsikon jokaiselle kategorialle.
+5. `ProductRow` (keltainen) näyttää rivin jokaiselle tuotteelle.
-If you look at `ProductTable` (lavender), you'll see that the table header (containing the "Name" and "Price" labels) isn't its own component. This is a matter of preference, and you could go either way. For this example, it is a part of `ProductTable` because it appears inside the `ProductTable`'s list. However, if this header grows to be complex (e.g., if you add sorting), you can move it into its own `ProductTableHeader` component.
+Jos katsot `ProductTable`:a (laventeli), huomaat että taulukon otsake (joka sisältää "Name" ja "Price") ei ole oma komponenttinsa. Tämä on mieltymyskysymys ja voisit tehdä tämän kummin päin tahansa. Tässä esimerkissä se on osa `ProductTable`:a koska se näkyy `ProductTable`:n listassa. Kuitenkin, jos tämä otsake kasvaa monimutkaiseksi (esim. jos lisäät suodattamisen), olisi järkevää tehdä siitä oma `ProductTableHeader` komponenttinsa.
-Now that you've identified the components in the mockup, arrange them into a hierarchy. Components that appear within another component in the mockup should appear as a child in the hierarchy:
+Nyt kun olet tunnistanut komponentit mallista, järjestä ne hierarkiaan. Komponentit, jotka näkyvät toisen komponentin sisällä mallissa, pitäisi olla lapsena hierarkiassa:
-* `FilterableProductTable`
- * `SearchBar`
- * `ProductTable`
- * `ProductCategoryRow`
- * `ProductRow`
+- `FilterableProductTable`
+ - `SearchBar`
+ - `ProductTable`
+ - `ProductCategoryRow`
+ - `ProductRow`
-## Step 2: Build a static version in React {/*step-2-build-a-static-version-in-react*/}
+## 2. Vaihe: Rakenna staattinen versio Reactissa {/*step-2-build-a-static-version-in-react*/}
-Now that you have your component hierarchy, it's time to implement your app. The most straightforward approach is to build a version that renders the UI from your data model without adding any interactivity... yet! It's often easier to build the static version first and add interactivity later. Building a static version requires a lot of typing and no thinking, but adding interactivity requires a lot of thinking and not a lot of typing.
+Nyt kun olet tehnyt komponenttihierarkian on aika toteuttaa sovelluksesi. Yksikertaisin tapa on rakentaa versio, joka renderöi käyttöliittymän tietomallista ilman interkatiivisuutta. Useiten on helpompi rakentaa staattinen versio ensin ja sitten lisätä interkatiivisuus jälkikäteen. Staattisen version rakentaminen vaatii paljon kirjoittamista muttei ajattelua, kuitenkin interaktiivisuuden lisääminen vaatii paljon ajattelua ja ei paljoa kirjoittamista.
-To build a static version of your app that renders your data model, you'll want to build [components](/learn/your-first-component) that reuse other components and pass data using [props.](/learn/passing-props-to-a-component) Props are a way of passing data from parent to child. (If you're familiar with the concept of [state](/learn/state-a-components-memory), don't use state at all to build this static version. State is reserved only for interactivity, that is, data that changes over time. Since this is a static version of the app, you don't need it.)
+Rakentaaksesi staattisen version sovelluksestasi, joka renderöi tietomallisi, käytä [komponentteja](/learn/your-first-component), jotka uudelleenkäyttävät toisia komponennteja ja välittävät tietoa käyttämällä [propseja.](/learn/passing-props-to-a-component) Propsit ovat tapa välittää tietoa pääkomponentilta alakomponentille. (Jos [tila](/learn/state-a-components-memory) on konseptina tuttu, älä käytä tilaa ollenkaan kun rakennat tämän staattisen version. Tila vaaditaan vain interaktiivisuuteen, eli kun tieto muuttuu ajan kuluessa. Kerta tämä on staattinen versio sovelluksta, et tarvitse sitä.)
-You can either build "top down" by starting with building the components higher up in the hierarchy (like `FilterableProductTable`) or "bottom up" by working from components lower down (like `ProductRow`). In simpler examples, it’s usually easier to go top-down, and on larger projects, it’s easier to go bottom-up.
+Voit rakentaa joko "ylhäältä alas" aloittamalla komponenteilla, jotka ovat hierarkiassa ylempänä (kuten `FilterableProductTable`) tai "alhaalta ylös" työstämällä komponentteja alhaalla (kuten `ProductRow`). Yksinkertaisin esimerkein, useimmiten on helpompi tehä ylhäältä alaspäin, kun taas suuremmissa projekteissa on helpompi tehdä alhaalta ylöspäin.
```jsx App.js
-function ProductCategoryRow({ category }) {
+function ProductCategoryRow({category}) {
return (
-
- {category}
-
+ {category}
);
}
-function ProductRow({ product }) {
- const name = product.stocked ? product.name :
-
- {product.name}
- ;
+function ProductRow({product}) {
+ const name = product.stocked ? (
+ product.name
+ ) : (
+ {product.name}
+ );
return (
@@ -106,7 +123,7 @@ function ProductRow({ product }) {
);
}
-function ProductTable({ products }) {
+function ProductTable({products}) {
const rows = [];
let lastCategory = null;
@@ -115,14 +132,11 @@ function ProductTable({ products }) {
rows.push(
+ key={product.category}
+ />
);
}
- rows.push(
-
- );
+ rows.push( );
lastCategory = product.category;
});
@@ -144,15 +158,13 @@ function SearchBar() {
);
}
-function FilterableProductTable({ products }) {
+function FilterableProductTable({products}) {
return (
@@ -162,12 +174,12 @@ function FilterableProductTable({ products }) {
}
const PRODUCTS = [
- {category: "Fruits", price: "$1", stocked: true, name: "Apple"},
- {category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit"},
- {category: "Fruits", price: "$2", stocked: false, name: "Passionfruit"},
- {category: "Vegetables", price: "$2", stocked: true, name: "Spinach"},
- {category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin"},
- {category: "Vegetables", price: "$1", stocked: true, name: "Peas"}
+ {category: 'Fruits', price: '$1', stocked: true, name: 'Apple'},
+ {category: 'Fruits', price: '$1', stocked: true, name: 'Dragonfruit'},
+ {category: 'Fruits', price: '$2', stocked: false, name: 'Passionfruit'},
+ {category: 'Vegetables', price: '$2', stocked: true, name: 'Spinach'},
+ {category: 'Vegetables', price: '$4', stocked: false, name: 'Pumpkin'},
+ {category: 'Vegetables', price: '$1', stocked: true, name: 'Peas'},
];
export default function App() {
@@ -177,7 +189,7 @@ export default function App() {
```css
body {
- padding: 5px
+ padding: 5px;
}
label {
display: block;
@@ -195,145 +207,142 @@ td {
-(If this code looks intimidating, go through the [Quick Start](/learn/) first!)
+(Jos tämä koodi näyttää pelottavalta, käy [Pika-aloitus](/learn/) läpi ensiksi!
-After building your components, you'll have a library of reusable components that render your data model. Because this is a static app, the components will only return JSX. The component at the top of the hierarchy (`FilterableProductTable`) will take your data model as a prop. This is called _one-way data flow_ because the data flows down from the top-level component to the ones at the bottom of the tree.
+Komponenttien rakentamisen jälkeen sinulta löytyy kirjasto uudelleenkäytettäviä komponentteja, jotka renderöivät tietomallisi. Sillä tämä on staattinn sovellus, komponentit ainoastaan palauttavat JSX:ää. Komponentit ylhäällä hierarkiassa (`FilterableProductTable`) saavat tietomallisi proppeina. Tätä kutsutaan _yksisuuntaiseksi tiedonkuluksi_ sillä tieto kulkee alas vain yläkomponenteista komponentteihin alhaalla puussa.
-At this point, you should not be using any state values. That’s for the next step!
+Tässä kohtaa sinun ei pitäisi käyttää mitään tila-arvoja. Se tulee seuraavassa vaiheessa!
-## Step 3: Find the minimal but complete representation of UI state {/*step-3-find-the-minimal-but-complete-representation-of-ui-state*/}
+## 3. Vaihe: Etsi minimaalinen, mutta täysinäinen mallinnus UI:n tilasta {/*step-3-find-the-minimal-but-complete-representation-of-ui-state*/}
-To make the UI interactive, you need to let users change your underlying data model. You will use *state* for this.
+Jotta voit tehdä käyttöliittymästä interaktiivisen, käyttäjien täytyy voida muuttaa taustalla olevaa tietomallia. Tähän tulet käyttämään _tilaa_.
-Think of state as the minimal set of changing data that your app needs to remember. The most important principle for structuring state is to keep it [DRY (Don't Repeat Yourself).](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) Figure out the absolute minimal representation of the state your application needs and compute everything else on-demand. For example, if you're building a shopping list, you can store the items as an array in state. If you want to also display the number of items in the list, don't store the number of items as another state value--instead, read the length of your array.
+Ajattele tilaa minimaalisena tiedon muutoksena, jota sovelluksesi täytyy muistaa. Tärkein periaate tilan järjestelyssä on pitää se kuivana [DRY (Don't Repeat Yourself).](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) Selvitä kaikista pienin kuvaus tilasta, jota sovelluksesi tarvitsee ja laske kaikki muu tarpeen vaatiessa. Esimerkiksi jos olet rakentamassa ostoslistaa, voit tallentaa kohteet taulukkona tilaan. Jos haluat myös näyttää myös määrän kohteista listalla, älä tallenna lukua toisena tila-arvona, vaan lue taulukon pituus.
-Now think of all of the pieces of data in this example application:
+Nyt ajattele kaikkia tiedonpalasia tässä esimerkkisovelluksessa:
-1. The original list of products
-2. The search text the user has entered
-3. The value of the checkbox
-4. The filtered list of products
+1. Alkupäinen lista tuotteista
+2. Hakulause, jonka käyttäjä on syöttänyt
+3. Valintaruudun arvo
+4. Lista suodatetuista tuotteista
-Which of these are state? Identify the ones that are not:
+Mitkä näistä ovat tiloja? Tunnista ne, jotka eivät ole:
-* Does it **remain unchanged** over time? If so, it isn't state.
-* Is it **passed in from a parent** via props? If so, it isn't state.
-* **Can you compute it** based on existing state or props in your component? If so, it *definitely* isn't state!
+- Pysyykö se **muuttumattona** ajan kuluessa? Jos näin, se ei ole tila.
+- Onko se **välitetty pääkomponentista** propsien avulla? Jos näin, se ei ole tila.
+- **Voitko laskea sen** alkuperäisen tilan tai propsien avulla komponentissasi? Jos näin, se ei _varmasti_ ole tila!
-What's left is probably state.
+Se mitä jää jäljelle on varmaankin tila.
-Let's go through them one by one again:
+Käydään ne vielä läpi yksitellen:
-1. The original list of products is **passed in as props, so it's not state.**
-2. The search text seems to be state since it changes over time and can't be computed from anything.
-3. The value of the checkbox seems to be state since it changes over time and can't be computed from anything.
-4. The filtered list of products **isn't state because it can be computed** by taking the original list of products and filtering it according to the search text and value of the checkbox.
+1. Alkuperäinen lista tuotteista **välitetään propseina, joten se ei ole tila.**
+2. Hakulause vaikuttaa olevan tila sillä se muuttuu ajan kuluessa eikä sitä voida laskea mistään.
+3. Valintaruudun arvo vaikuttaa olevan tila sillä se muuttuu ajan kuluessa eikä sitä voida laskea mistään.
+4. Lista suodatetuista tuotteista **ei ole tila sillä se voidaan laskea** alkuperäisestä tuotelistasta suodattamalla hakulauseen ja valintaruudun perusteella.
-This means only the search text and the value of the checkbox are state! Nicely done!
+Tämä tarkoittaa, että vain hakulause ja valintaruudun arvo ovat tiloja. Hienosti tehty!
-#### Props vs State {/*props-vs-state*/}
+#### Propsit vs Tila {/*props-vs-state*/}
-There are two types of "model" data in React: props and state. The two are very different:
+On kaksi "mallia" tietoa Reactissa: propsit ja tila. Nämä kaksi poikkeavat toisistaan:
-* [**Props** are like arguments you pass](/learn/passing-props-to-a-component) to a function. They let a parent component pass data to a child component and customize its appearance. For example, a `Form` can pass a `color` prop to a `Button`.
-* [**State** is like a component’s memory.](/learn/state-a-components-memory) It lets a component keep track of some information and change it in response to interactions. For example, a `Button` might keep track of `isHovered` state.
+- [**Propsit** ovat kuin argumentteja, joita välität](/learn/passing-props-to-a-component) funktiolle. Niillä pääkomponentti välittää tietoa alakomponentille ja mukauttaa sen ulkoasua. Esimerkiksi `Form` komponentti voi välittää `color` propin `Button` komponentille.
+- [**Tila** on kuin komponentin muisti.](/learn/state-a-components-memory) Sillä komponentti voi seurata jotain tietoa ja muuttaa sitä tapahtumien perusteella. Esimerkiksi `Button` komponetti voi seurata `isHovered` tilaa.
-Props and state are different, but they work together. A parent component will often keep some information in state (so that it can change it), and *pass it down* to child components as their props. It's okay if the difference still feels fuzzy on the first read. It takes a bit of practice for it to really stick!
+Propsit ja tila ovat eri asioita, mutta ne toimivat yhdesäs. Pääkomponentti usei pitää jotain tietoa tilassa (jotta se voi muuttaa sitä), ja _välittää ne alas_ alakomponenteille niiden propseina. On okei jos näiden ero tuntuu epämääräiseltä ensimmäisellä lukukerralla. Tämä saattaa vaatia vähän harjoittelua.
-## Step 4: Identify where your state should live {/*step-4-identify-where-your-state-should-live*/}
+## 4. Vaihe: Tunnista missä tilan kuuluisi elää {/*step-4-identify-where-your-state-should-live*/}
-After identifying your app’s minimal state data, you need to identify which component is responsible for changing this state, or *owns* the state. Remember: React uses one-way data flow, passing data down the component hierarchy from parent to child component. It may not be immediately clear which component should own what state. This can be challenging if you’re new to this concept, but you can figure it out by following these steps!
+Kun olet tunnistanut sovelluksesi minimaalisen tilan, täytyy tunnistaa mikä komponentti on vastuussa tilan muuttamisesta, tai _omistaa_ tilan. Muista: React käyttää yksisuuntaista tiedonkulkua välittäen tietoa alaspäin komponenttihierarkiassa pääkomponentilta alakomponentille. Se ei välttämättä heti aluksi ole selkeää minkä komponentin pitäisi omistaa mitäkin tilaa. Tämä saattaa olla haastaa jos konsepti on uusi, mutta voit selvittää sen seuraavilla ohjeilla!
-For each piece of state in your application:
+Jokaiselle palalle tilaa sovelluksessasi:
-1. Identify *every* component that renders something based on that state.
-2. Find their closest common parent component--a component above them all in the hierarchy.
-3. Decide where the state should live:
- 1. Often, you can put the state directly into their common parent.
- 2. You can also put the state into some component above their common parent.
- 3. If you can't find a component where it makes sense to own the state, create a new component solely for holding the state and add it somewhere in the hierarchy above the common parent component.
+1. Tunnista _jokainen_ komponentti, joka renderöi jotain sen tilan pohjalta.
+2. Etsi niiden lähin yhteinen pääkomponentti--komponentti kaikkien niiden yläpuolella hierarkiassa.
+3. Päätä missä tilan kuuluisi elää:
+ 1. Usei voit laittaa tilan suoraan yhteiseen pääkomponenttiin.
+ 2. Voit myös laittaa tilan yhteistä pääkomponenttia korkeammalle.
+ 3. Jos et löydä komponenttia, jonka olisi järkevä omistaa tila, luo uusi komponentti pelkästään ylläpitämään tilaa ja lisää se jonnekkin hierarkiassa yhteisen pääkomponentin yläpuolelle.
-In the previous step, you found two pieces of state in this application: the search input text, and the value of the checkbox. In this example, they always appear together, so it makes sense to put them into the same place.
+Edellisessä vaiheessa sait kaksi tilan palaa sovelluksessa: hakulauseen sekä valintaruudun arvon. Tässä esimerkissä molemmat näkyvät yhdessä, jotta on helpompi ajatella niitä yksittäisenä palana tilaa.
-Now let's run through our strategy for them:
+Käydään läpi strategiaa tälle tilalle:
-1. **Identify components that use state:**
- * `ProductTable` needs to filter the product list based on that state (search text and checkbox value).
- * `SearchBar` needs to display that state (search text and checkbox value).
-1. **Find their common parent:** The first parent component both components share is `FilterableProductTable`.
-2. **Decide where the state lives**: We'll keep the filter text and checked state values in `FilterableProductTable`.
+1. **Tunnista komponentit, jotka käyttävät tilaa:**
+ - `ProductTable`:n täytyy suodataa tuotelista tilan perusteella (hakulauseella ja valintaruudun arvolla).
+ - `SearchBar`:n täytyy näyttää tila (hakulause ja valintaruudun arvo).
+2. **Etsi niiden yhteinen pääkomponentti:** Ensimmäinen komponentti, jonka molemmat jakavat on `FilterableProductTable`.
+3. **Päätä missä tila elää**: Pidämme hakulauseen ja valintaruudun arvon `FilterableProductTable` komponentissa.
-So the state values will live in `FilterableProductTable`.
+Joten tila elää `FilterableProductTable` komponentissa.
-Add state to the component with the [`useState()` Hook.](/reference/react/useState) Hooks are special functions that let you "hook into" React. Add two state variables at the top of `FilterableProductTable` and specify their initial state:
+Lisää tila komponenttiin käyttämällä [`useState()` Hookkia.](/reference/react/useState) Hookit ovat erityisiä funktioita, joiden avulla pääset käsiksi Reactiin. Lisä kaksi tilamuuttujaa `FilterableProductTable` komponentin yläosassa ja määritä sovelluksesi aloitusarvot:
```js
function FilterableProductTable({ products }) {
const [filterText, setFilterText] = useState('');
- const [inStockOnly, setInStockOnly] = useState(false);
+ const [inStockOnly, setInStockOnly] = useState(false);
```
-Then, pass `filterText` and `inStockOnly` to `ProductTable` and `SearchBar` as props:
+Sitten välitä `filterText` ja `inStockOnly` komponenteille `ProductTable` ja `SearchBar` propseina:
```js
-
-
+
+ inStockOnly={inStockOnly}
+ />
```
-You can start seeing how your application will behave. Edit the `filterText` initial value from `useState('')` to `useState('fruit')` in the sandbox code below. You'll see both the search input text and the table update:
+Alat näkemään miten sovelluksesi tulee käyttäytymään. Muokkaa `filterText` oletusarvoa arvosta `useState('')` arvoon `useState('fruit')` hiekkalaatikossa alla. Näet sekä hakulaatikon että taulukon päivittyvän:
```jsx App.js
-import { useState } from 'react';
+import {useState} from 'react';
-function FilterableProductTable({ products }) {
+function FilterableProductTable({products}) {
const [filterText, setFilterText] = useState('');
const [inStockOnly, setInStockOnly] = useState(false);
return (
-
-
+
+ inStockOnly={inStockOnly}
+ />
);
}
-function ProductCategoryRow({ category }) {
+function ProductCategoryRow({category}) {
return (
-
- {category}
-
+ {category}
);
}
-function ProductRow({ product }) {
- const name = product.stocked ? product.name :
-
- {product.name}
- ;
+function ProductRow({product}) {
+ const name = product.stocked ? (
+ product.name
+ ) : (
+ {product.name}
+ );
return (
@@ -343,16 +352,12 @@ function ProductRow({ product }) {
);
}
-function ProductTable({ products, filterText, inStockOnly }) {
+function ProductTable({products, filterText, inStockOnly}) {
const rows = [];
let lastCategory = null;
products.forEach((product) => {
- if (
- product.name.toLowerCase().indexOf(
- filterText.toLowerCase()
- ) === -1
- ) {
+ if (product.name.toLowerCase().indexOf(filterText.toLowerCase()) === -1) {
return;
}
if (inStockOnly && !product.stocked) {
@@ -362,14 +367,11 @@ function ProductTable({ products, filterText, inStockOnly }) {
rows.push(
+ key={product.category}
+ />
);
}
- rows.push(
-
- );
+ rows.push( );
lastCategory = product.category;
});
@@ -386,31 +388,25 @@ function ProductTable({ products, filterText, inStockOnly }) {
);
}
-function SearchBar({ filterText, inStockOnly }) {
+function SearchBar({filterText, inStockOnly}) {
return (
);
}
const PRODUCTS = [
- {category: "Fruits", price: "$1", stocked: true, name: "Apple"},
- {category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit"},
- {category: "Fruits", price: "$2", stocked: false, name: "Passionfruit"},
- {category: "Vegetables", price: "$2", stocked: true, name: "Spinach"},
- {category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin"},
- {category: "Vegetables", price: "$1", stocked: true, name: "Peas"}
+ {category: 'Fruits', price: '$1', stocked: true, name: 'Apple'},
+ {category: 'Fruits', price: '$1', stocked: true, name: 'Dragonfruit'},
+ {category: 'Fruits', price: '$2', stocked: false, name: 'Passionfruit'},
+ {category: 'Vegetables', price: '$2', stocked: true, name: 'Spinach'},
+ {category: 'Vegetables', price: '$4', stocked: false, name: 'Pumpkin'},
+ {category: 'Vegetables', price: '$1', stocked: true, name: 'Peas'},
];
export default function App() {
@@ -420,7 +416,7 @@ export default function App() {
```css
body {
- padding: 5px
+ padding: 5px;
}
label {
display: block;
@@ -437,7 +433,7 @@ td {
-Notice that editing the form doesn't work yet. There is a console error in the sandbox above explaining why:
+Huomaa, että lomakkeen muokkaaminen ei toimi vielä. Hiekkalaatikon konsolissa on virhe, joka kertoo miksi:
@@ -445,28 +441,27 @@ You provided a \`value\` prop to a form field without an \`onChange\` handler. T
-In the sandbox above, `ProductTable` and `SearchBar` read the `filterText` and `inStockOnly` props to render the table, the input, and the checkbox. For example, here is how `SearchBar` populates the input value:
+Ylläolevassa hiekkalaatikossa, `ProductTable` ja `SearchBar` lukevat `filterText` ja `inStockOnly` propsit renderöidäkseen taulukon, syöttölaatikon sekä valintaruudun. Esimerkiksi tässä on miten `SearchBar` täyttää syöttölaatikon arvon:
```js {1,6}
function SearchBar({ filterText, inStockOnly }) {
return (