{"componentChunkName":"component---src-templates-content-template-js","path":"/osa6/redux_legacy","result":{"data":{"markdownRemark":{"html":"<div class=\"tasks\">\n<p>Tämä on kurssin jo käytöstä poistettu Reduxiin liittyvä materiaali. Voit jatkaa tämän matariaalin ja siinä olevien tehtävien tekemistä jos olet jo aloittanut osan tekemisen Reduxilla. Muussa tapauksessa kannattaa seurata uutta materiaalia. Tämä materiaali poistuu näkyvistä kesäkuusa 2026.</p>\n</div>\n<div class=\"content\">\n<p>Olemme noudattaneet sovelluksen tilan hallinnassa Reactin suosittelemaa käytäntöä määritellä useiden komponenttien tarvitsema tila ja sitä käsittelevät funktiot sovelluksen komponenttirakenteen <a href=\"https://reactjs.org/docs/lifting-state-up.html\">ylimmissä</a> kompontenteissa. Usein suurin osa tilaa ja sitä käsittelevistä funktioista on määritelty suoraan sovelluksen juurikomponentissa ja välitetty propsien avulla niitä tarvitseville komponenteille. Tämä toimii johonkin pisteeseen saakka, mutta sovelluksen kasvaessa tilan hallinta muuttuu haasteelliseksi.</p>\n<h3>Flux-arkkitehtuuri</h3>\n<p>Facebook kehitti jo Reactin historian varhaisvaiheissa tilan hallinnan ongelmia helpottamaan <a href=\"https://facebookarchive.github.io/flux/docs/in-depth-overview\">Flux</a>-arkkitehtuurin. Fluxissa sovelluksen tilan hallinta erotetaan kokonaan Reactin komponenttien ulkopuolisiin varastoihin eli <i>storeihin</i>. Storessa olevaa tilaa ei muuteta suoraan, vaan tapahtumien eli <i>actionien</i> avulla.</p>\n<p>Kun action muuttaa storen tilaa, renderöidään näkymät uudelleen:</p>\n<picture><img src=\"/static/165b40470776ac449f8b9604d4828004/5a190/flux1.png\" alt=\"Action -> Dispatcher -> Store -> View\" srcset=\"/static/165b40470776ac449f8b9604d4828004/772e8/flux1.png 200w,\n/static/165b40470776ac449f8b9604d4828004/e17e5/flux1.png 400w,\n/static/165b40470776ac449f8b9604d4828004/5a190/flux1.png 800w,\n/static/165b40470776ac449f8b9604d4828004/c1b63/flux1.png 1200w,\n/static/165b40470776ac449f8b9604d4828004/29007/flux1.png 1600w,\n/static/165b40470776ac449f8b9604d4828004/090a8/flux1.png 2504w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Jos sovelluksen käyttö (esim. napin painaminen) aiheuttaa tarpeen tilan muutokseen, tehdään muutos actionin avulla. Tämä taas aiheuttaa uuden näytön renderöitymisen:</p>\n<picture><img src=\"/static/7bf90479b6757c7af3b9a9f0e7f19a64/5a190/flux2.png\" alt=\"Action -> Dispatcher -> Store -> View -> Action -> Dispatcher -> View\" srcset=\"/static/7bf90479b6757c7af3b9a9f0e7f19a64/772e8/flux2.png 200w,\n/static/7bf90479b6757c7af3b9a9f0e7f19a64/e17e5/flux2.png 400w,\n/static/7bf90479b6757c7af3b9a9f0e7f19a64/5a190/flux2.png 800w,\n/static/7bf90479b6757c7af3b9a9f0e7f19a64/c1b63/flux2.png 1200w,\n/static/7bf90479b6757c7af3b9a9f0e7f19a64/29007/flux2.png 1600w,\n/static/7bf90479b6757c7af3b9a9f0e7f19a64/a5262/flux2.png 2388w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Flux tarjoaa siis standardin tavan sille miten ja missä sovelluksen tila pidetään sekä tavalle tehdä tilaan muutoksia.</p>\n<h3>Redux</h3>\n<p>Facebookilla on olemassa valmis toteutus Fluxille, mutta käytämme kuitenkin saman periaatteen mukaan toimivaa mutta hieman yksinkertaisempaa <a href=\"https://redux.js.org\">Redux</a>-kirjastoa, jota myös Facebookilla käytetään nykyään alkuperäisen Flux-toteutuksen sijaan.</p>\n<p>Tutustutaan Reduxiin tekemällä jälleen kerran laskurin toteuttava sovellus:</p>\n<picture><img src=\"/static/840092f1209e6650c1989aaf0c143817/5a190/1.png\" alt=\"Renderöity kokonaisluku sekä kolme nappia: plus, minus ja zero\" srcset=\"/static/840092f1209e6650c1989aaf0c143817/772e8/1.png 200w,\n/static/840092f1209e6650c1989aaf0c143817/e17e5/1.png 400w,\n/static/840092f1209e6650c1989aaf0c143817/5a190/1.png 800w,\n/static/840092f1209e6650c1989aaf0c143817/c1b63/1.png 1200w,\n/static/840092f1209e6650c1989aaf0c143817/4352a/1.png 1364w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Tehdään uusi Vite‑sovellus ja asennetaan siihen <i>Redux</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> redux</code></pre></div>\n<p>Fluxin tapaan Reduxissa sovelluksen tila talletetaan <a href=\"https://redux.js.org/basics/store\">storeen</a>.</p>\n<p>Koko sovelluksen tila talletetaan <i>yhteen</i> storen tallettamaan JavaScript-objektiin. Koska sovelluksemme ei tarvitse mitään muuta tilaa kuin laskurin arvon, talletetaan se storeen sellaisenaan. Jos sovelluksen tila olisi monimutkaisempi, talletettaisiin \"eri asiat\" storessa olevaan olioon erillisinä kenttinä.</p>\n<p>Storen tilaa muutetaan <a href=\"https://redux.js.org/basics/actions\">actionien</a> avulla. Actionit ovat olioita, joilla on vähintään actionin <i>tyypin</i> määrittelevä kenttä <i>type</i>. Sovelluksessamme tarvitsemme esimerkiksi seuraavaa actionia:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'INCREMENT'</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Jos actioneihin liittyy dataa, määritellään niille tarpeen vaatiessa muitakin kenttiä. Laskurisovelluksemme on kuitenkin niin yksinkertainen, että actioneille riittää pelkkä tyyppikenttä.</p>\n<p>Actionien vaikutus sovelluksen tilaan määritellään <a href=\"https://redux.js.org/basics/reducers\">reducerin</a> avulla. Käytännössä reducer on funktio, joka saa parametrikseen staten nykyisen tilan sekä actionin ja <i>palauttaa</i> staten uuden tilan.</p>\n<p>Määritellään nyt sovelluksellemme reducer tiedostoon <i>main.jsx</i>. Tiedosto näyttää aluksi seuraavalta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">counterReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type <span class=\"token operator\">===</span> <span class=\"token string\">'INCREMENT'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> state <span class=\"token operator\">+</span> <span class=\"token number\">1</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type <span class=\"token operator\">===</span> <span class=\"token string\">'DECREMENT'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> state <span class=\"token operator\">-</span> <span class=\"token number\">1</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type <span class=\"token operator\">===</span> <span class=\"token string\">'ZERO'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token number\">0</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> state\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Ensimmäinen parametri on siis storessa oleva <i>tila</i>. Reducer palauttaa <i>uuden tilan</i> actionin tyypin mukaan. Eli esim. actionin tyypin ollessa <i>INCREMENT</i> tila saa arvokseen vanhan arvon plus yksi. Jos actionin tyyppi on <i>ZERO</i> tilan uusi arvo on nolla.</p>\n<p>Muutetaan koodia vielä hiukan. Reducereissa on tapana käyttää if:ien sijaan <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch\">switch</a>-komentoa.\nMääritellään myös parametrille <i>state</i> <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters\">oletusarvoksi</a> 0. Näin reducer toimii vaikka storen tilaa ei olisi vielä alustettu.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">counterReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'INCREMENT'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state <span class=\"token operator\">+</span> <span class=\"token number\">1</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'DECREMENT'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state <span class=\"token operator\">-</span> <span class=\"token number\">1</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'ZERO'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> <span class=\"token number\">0</span>\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span> <span class=\"token comment\">// jos ei mikään ylläolevista tullaan tänne</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Reduceria ei ole tarkoitus kutsua koskaan suoraan sovelluksen koodista. Reducer ainoastaan annetaan parametrina storen luovalle <em>createStore</em>-funktiolle:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'redux'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">counterReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'INCREMENT'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state <span class=\"token operator\">+</span> <span class=\"token number\">1</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'DECREMENT'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state <span class=\"token operator\">-</span> <span class=\"token number\">1</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'ZERO'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> <span class=\"token number\">0</span>\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>counterReducer<span class=\"token punctuation\">)</span></span></code></pre></div>\n<p>Koodieditori saattaa huomauttaa, että <em>createStore</em> on vanhentunut. Ei välitetä siitä toistaiseksi, alempana on tarkempi selitys asiasta.</p>\n<p>Store käyttää nyt reduceria käsitelläkseen <i>actioneja</i>, jotka <i>dispatchataan</i> eli \"lähetetään\" storelle sen <a href=\"https://redux.js.org/api/store#dispatchaction\">dispatch</a>-metodilla:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'INCREMENT'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Storen tilan saa selville metodilla <a href=\"https://redux.js.org/api/store/#getstate\">getState</a>.</p>\n<p>Esim. seuraava koodi</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// ...</span>\n\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>counterReducer<span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\">console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'INCREMENT'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'INCREMENT'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'INCREMENT'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'ZERO'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'DECREMENT'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span></code></pre></div>\n<p>tulostaisi konsoliin</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">0\n3\n-1</code></pre></div>\n<p>sillä ensin storen tila on 0. Kolmen <i>INCREMENT</i>-actionin jälkeen tila on 3, ja lopulta actionien <i>ZERO</i> ja <i>DECREMENT</i> jälkeen -1.</p>\n<p>Kolmas storen tärkeä metodi on <a href=\"https://redux.js.org/api/store#subscribelistener\">subscribe</a>, jonka avulla voidaan määritellä takaisinkutsufunktioita, joita store kutsuu sen tilan muuttumisen yhteydessä.</p>\n<p>Esimerkkinä voisimme tulostaa <i>jokaisen storen muutoksen</i> konsoliin näin:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">store<span class=\"token punctuation\">.</span><span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> storeNow <span class=\"token operator\">=</span> store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>storeNow<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Tällöin koodi</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// ...</span>\n\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>counterReducer<span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> storeNow <span class=\"token operator\">=</span> store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>storeNow<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>\n<span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'INCREMENT'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'INCREMENT'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'INCREMENT'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'ZERO'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'DECREMENT'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span></code></pre></div>\n<p>tulostaisi</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">1\n2\n3\n0\n-1</code></pre></div>\n<p>Laskurisovelluksemme koodi on seuraavassa. Kaikki koodi on kirjoitettu samaan tiedostoon, joten <i>store</i> on suoraan React-koodin käytettävissä. Tutustumme React/Redux-koodin parempiin strukturointitapoihin myöhemmin. Tiedoston <i>main.jsx</i> sisältö näyttää seuraavalta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom/client'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'redux'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">counterReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'INCREMENT'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state <span class=\"token operator\">+</span> <span class=\"token number\">1</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'DECREMENT'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state <span class=\"token operator\">-</span> <span class=\"token number\">1</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'ZERO'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> <span class=\"token number\">0</span>\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>counterReducer<span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'INCREMENT'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        plus\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'DECREMENT'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        minus\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'ZERO'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        zero\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> root <span class=\"token operator\">=</span> ReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">createRoot</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'root'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">renderApp</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  root<span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&lt;</span>App <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token function\">renderApp</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\nstore<span class=\"token punctuation\">.</span><span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span>renderApp<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Koodissa on pari huomionarvoista seikkaa. <i>App</i> renderöi laskurin arvon kysymällä sitä storesta metodilla <em>store.getState()</em>. Nappien tapahtumankäsittelijät <i>dispatchaavat</i> suoraan oikean tyyppiset actionit storelle.</p>\n<p>Kun storessa olevan tilan arvo muuttuu, ei React osaa automaattisesti renderöidä sovellusta uudelleen. Olemmekin rekisteröineet koko sovelluksen renderöinnin suorittavan funktion <em>renderApp</em> kuuntelemaan storen muutoksia metodilla <em>store.subscribe</em>. Huomaa, että joudumme kutsumaan heti alussa metodia <em>renderApp</em>, sillä ilman kutsua sovelluksen ensimmäistä renderöintiä ei tapahdu ollenkaan.</p>\n<h3>Huomautus funktion createStore käytöstä</h3>\n<p>Tarkkasilmäisimmät huomaavat, että funktion createStore nimen päällä on viiva. Jos hiiren vie nimen päälle, tulee asialle selitystä </p>\n<picture><img src=\"/static/8f7b66c42fce3d8286e1c8923bbae0b4/5a190/30new.png\" srcset=\"/static/8f7b66c42fce3d8286e1c8923bbae0b4/772e8/30new.png 200w,\n/static/8f7b66c42fce3d8286e1c8923bbae0b4/e17e5/30new.png 400w,\n/static/8f7b66c42fce3d8286e1c8923bbae0b4/5a190/30new.png 800w,\n/static/8f7b66c42fce3d8286e1c8923bbae0b4/c1b63/30new.png 1200w,\n/static/8f7b66c42fce3d8286e1c8923bbae0b4/6bfbb/30new.png 1514w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Selitys on kokonaisuudessaan seuraava</p>\n<blockquote>\n<p><i>We recommend using the configureStore method of the @reduxjs/toolkit package, which replaces createStore.</i></p>\n<p><i>Redux Toolkit is our recommended approach for writing Redux logic today, including store setup, reducers, data fetching, and more.</i></p>\n<p><i>For more details, please read this Redux docs page: <a href=\"https://redux.js.org/introduction/why-rtk-is-redux-today\">https://redux.js.org/introduction/why-rtk-is-redux-today</a></i></p>\n<p><i>configureStore from Redux Toolkit is an improved version of createStore that simplifies setup and helps avoid common bugs.</i></p>\n<p><i>You should not be using the redux core package by itself today, except for learning purposes. The createStore method from the core redux package will not be removed, but we encourage all users to migrate to using Redux Toolkit for all Redux code.</i></p>\n</blockquote>\n<p>Funktion <i>createStore</i> sijaan siis suositellaan käytettäväksi hieman \"kehittyneempää\" funktiota <i>configureStore</i>, ja mekin tulemme ottamaan sen käyttöömme kun olemme ottaneet Reduxin perustoiminnallisuuden haltuun.</p>\n<p>Sivuhuomio: <i>createStore</i> on määritelty olevan \"deprecated\", joka yleensä tarkoittaa sitä, että ominaisuus tulee poistumaan kirjaston jossain uudemmassa versiossa. Yllä oleva selitys ja <a href=\"https://stackoverflow.com/questions/71944111/redux-createstore-is-deprecated-cannot-get-state-from-getstate-in-redux-ac\">tämäkin</a> keskustelu paljastavat, että <i>createStore</i> ei tule poistumaan, ja sille onkin annettu ehkä hieman virheellisin perustein status <i>deprecated</i>. Funktio ei siis ole vanhentunut, mutta nykyään on olemassa suositeltavampi, uusi tapa tehdä suunnilleen sama asia.</p>\n<h3>Redux-muistiinpanot</h3>\n<p>Tavoitteenamme on muuttaa muistiinpanosovellus käyttämään tilanhallintaan Reduxia. Katsotaan kuitenkin ensin eräitä konsepteja hieman yksinkertaistetun muistiinpanosovelluksen kautta.</p>\n<p>Sovelluksen ensimmäinen versio tiedostossa <i>main.jsx</i> on seuraava:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom/client'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'redux'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">noteReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token operator\">:</span>\n      state<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">return</span> state\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>noteReducer<span class=\"token punctuation\">)</span>\n\nstore<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'the app state is in redux store'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\nstore<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'state changes are made with actions'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n          <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n            <span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span> <span class=\"token operator\">&lt;</span>strong<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>important <span class=\"token operator\">?</span> <span class=\"token string\">'important'</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>strong<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> root <span class=\"token operator\">=</span> ReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">createRoot</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'root'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">renderApp</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  root<span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&lt;</span>App <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token function\">renderApp</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\nstore<span class=\"token punctuation\">.</span><span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span>renderApp<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Toistaiseksi sovelluksessa ei siis ole toiminnallisuutta uusien muistiinpanojen lisäämiseen, mutta voimme toteuttaa sen dispatchaamalla <i>NEW_NOTE</i>-tyyppisiä actioneja koodista.</p>\n<p>Actioneissa on nyt tyypin lisäksi kenttä <i>payload</i>, joka sisältää lisättävän muistiinpanon:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'state changes are made with actions'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Kentän nimen valinta ei ole sattumanvarainen. Yleinen konventio on, että actioneilla on juurikin kaksi kenttää, tyypin kertova <i>type</i> ja actionin mukana olevan tiedon sisältävä <i>payload</i>.</p>\n<h3>Puhtaat funktiot ja muuttumattomat (immutable) oliot</h3>\n<p>Reducerimme alustava versio on yksinkertainen:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">noteReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token operator\">:</span>\n      state<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">return</span> state\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Tila on nyt taulukko. <i>NEW_NOTE</i>-tyyppisen actionin seurauksena tilaan lisätään uusi muistiinpano metodilla <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push\">push</a>.</p>\n<p>Sovellus näyttää toimivan, mutta määrittelemämme reduceri on huono, sillä se rikkoo Reduxin reducerien <a href=\"https://redux.js.org/tutorials/essentials/part-1-overview-concepts#reducers\">perusolettamusta</a> siitä, että reducerien tulee olla <a href=\"https://en.wikipedia.org/wiki/Pure_function\">puhtaita funktioita</a>.</p>\n<p>Puhtaat funktiot ovat sellaisia, että ne <i>eivät aiheuta mitään sivuvaikutuksia</i> ja ne palauttavat aina saman vastauksen samoilla parametreilla kutsuttaessa.</p>\n<p>Lisäsimme tilaan uuden muistiinpanon metodilla <em>state.push(action.payload)</em>, joka <i>muuttaa</i> state-olion tilaa. Tämä ei ole sallittua. Ongelman voi korjata helposti käyttämällä metodia <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat\">concat</a>, joka luo <i>uuden taulukon</i>, jonka sisältönä on vanhan taulukon alkiot sekä lisättävä alkio:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">noteReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token operator\">:</span>\n<span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">concat</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span></span>    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Reducerin tilan tulee koostua muuttumattomista eli <a href=\"https://en.wikipedia.org/wiki/Immutable_object\">immutable</a>-olioista. Jos tilaan tulee muutos, ei vanhaa oliota muuteta, vaan se <i>korvataan uudella muuttuneella oliolla</i>. Juuri näin toimimme uudistuneessa reducerissa, eli vanha taulukko korvaantuu uudella.</p>\n<p>Laajennetaan reduceria siten, että se osaa käsitellä muistiinpanon tärkeyteen liittyvän muutoksen:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Koska meillä ei ole vielä koodia joka käyttää ominaisuutta, laajennetaan reduceria testivetoisesti.</p>\n<h3>Testiympäristön konfigurointi</h3>\n<p>Konfiguroidaan sovellukseen <a href=\"https://vitest.dev/\">Vitest</a>. Asennetaan se sovelluksen kehityksenaikaiseksi riippuvuudeksi:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">npm install <span class=\"token operator\">--</span>save<span class=\"token operator\">-</span>dev vitest</code></pre></div>\n<p>Lisätään tiedostoon <i>package.json</i> testit suorittava skripti:</p>\n<div class=\"gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// ...</span>\n  <span class=\"token property\">\"scripts\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"dev\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"vite\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"build\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"vite build\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"lint\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"eslint .\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"preview\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"vite preview\"</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token property\">\"test\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"vitest\"</span></span>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Jotta testaus olisi helpompaa, siirretään reducerin koodi ensin omaan moduuliinsa tiedostoon <i>src/reducers/noteReducer.js</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">noteReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">concat</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> noteReducer</code></pre></div>\n<p>Tiedosto <i>main.jsx</i> muuttuu seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom/client'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'redux'</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> noteReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span></span>\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>noteReducer<span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\">// ...</span></code></pre></div>\n<p> Otetaan lisäksi käyttöön kirjasto <a href=\"https://www.npmjs.com/package/deep-freeze\">deep-freeze</a>, jonka avulla voimme varmistaa, että reducer on määritelty oikeaoppisesti puhtaana funktiona. Asennetaan kirjasto kehitysaikaiseksi riippuvuudeksi:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">npm install <span class=\"token operator\">--</span>save<span class=\"token operator\">-</span>dev deep<span class=\"token operator\">-</span>freeze</code></pre></div>\n<p>Olemme nyt valmiita kirjoittamaan testejä. </p>\n<h3>Testit noteReducerille</h3>\n<p>Aloitetaan tekemällä testi actionin <i>NEW_NOTE</i> käsittelylle. Määritellään testi tiedostoon <i>src/reducers/noteReducer.test.js</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> deepFreeze <span class=\"token keyword\">from</span> <span class=\"token string\">'deep-freeze'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> describe<span class=\"token punctuation\">,</span> expect<span class=\"token punctuation\">,</span> test <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'vitest'</span>\n<span class=\"token keyword\">import</span> noteReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./noteReducer'</span>\n\n<span class=\"token function\">describe</span><span class=\"token punctuation\">(</span><span class=\"token string\">'noteReducer'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token string\">'returns new state with action NEW_NOTE'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token keyword\">const</span> action <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'the app state is in redux store'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token function\">deepFreeze</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">const</span> newState <span class=\"token operator\">=</span> <span class=\"token function\">noteReducer</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">)</span>\n\n    <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toHaveLength</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span>\n    <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toContainEqual</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Suoritetaan testi komennolla <em>npm test</em>. Testi siis varmistaa, että reducerin palauttama uusi tila on taulukko, joka sisältää yhden elementin, joka on sama kun actionin kentän <i>payload</i> sisältävä olio.</p>\n<p>Komento <i>deepFreeze(state)</i> varmistaa, että reducer ei muuta parametrina olevaa storen tilaa. Jos reducer käyttäisi tilan manipulointiin komentoa <em>push</em>, testi ei menisi läpi:</p>\n<picture><img src=\"/static/117a27f8d247283e7533da76f985ff64/5a190/2.png\" alt=\"Testi aiheuttaa virheilmoituksen TypeError: Can not add property 0, object is not extensible. Syynä komento state.push(action.payload)\" srcset=\"/static/117a27f8d247283e7533da76f985ff64/772e8/2.png 200w,\n/static/117a27f8d247283e7533da76f985ff64/e17e5/2.png 400w,\n/static/117a27f8d247283e7533da76f985ff64/5a190/2.png 800w,\n/static/117a27f8d247283e7533da76f985ff64/f32b7/2.png 1136w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Tehdään sitten testi actionin <i>TOGGLE_IMPORTANCE</i> käsittelylle:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token string\">'returns new state with action TOGGLE_IMPORTANCE'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'the app state is in redux store'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'state changes are made with actions'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span>\n\n  <span class=\"token keyword\">const</span> action <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">deepFreeze</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> newState <span class=\"token operator\">=</span> <span class=\"token function\">noteReducer</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toHaveLength</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toContainEqual</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toContainEqual</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'state changes are made with actions'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Eli seuraavan actionin</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>tulee muuttaa tärkeys muistiinpanolle, jonka id on 2.</p>\n<p>Reducer laajenee seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">noteReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">concat</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">case</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">const</span> id <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">.</span>id</span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">const</span> noteToChange <span class=\"token operator\">=</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">n</span> <span class=\"token operator\">=></span> n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> id<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">const</span> changedNote <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">...</span>noteToChange<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>noteToChange<span class=\"token punctuation\">.</span>important</span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id <span class=\"token operator\">?</span> note <span class=\"token operator\">:</span> changedNote<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span></span>    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Luomme tärkeyttä muuttaneesta muistiinpanosta kopion osasta 2 <a href=\"/osa2/palvelimella_olevan_datan_muokkaaminen#muistiinpanon-tarkeyden-muutos\">tutulla syntaksilla</a> ja korvaamme tilan uudella tilalla, johon otetaan muuttumattomat muistiinpanot ja muutettavasta sen muutettu kopio <i>changedNote</i>.</p>\n<p>Kerrataan vielä mitä koodissa tapahtuu. Ensin etsitään olio, jonka tärkeys on tarkoitus muuttaa:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> noteToChange <span class=\"token operator\">=</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">n</span> <span class=\"token operator\">=></span> n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> id<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Luodaan sitten uusi olio, joka on muuten <i>kopio</i> muuttuvasta oliosta mutta kentän <i>important</i> arvo on muutettu päinvastaiseksi:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> changedNote <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> \n  <span class=\"token operator\">...</span>noteToChange<span class=\"token punctuation\">,</span> \n  <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>noteToChange<span class=\"token punctuation\">.</span>important \n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Lopuksi palautetaan uusi tila. Se saadaan valitsemalla kaikki vanhan tilan muistiinpanot pois lukien etsittävää <i>id</i>:tä vastaava muistiinpano, jonka tilalle valitaan juuri muokattu muistiinpano:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">state<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id <span class=\"token operator\">?</span> note <span class=\"token operator\">:</span> changedNote<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3>Array spread ‑syntaksi</h3>\n<p>Koska reducerille on nyt suhteellisen hyvät testit, voimme refaktoroida koodia turvallisesti.</p>\n<p>Uuden muistiinpanon lisäys luo palautettavan tilan taulukon <em>concat</em>-funktiolla. Katsotaan nyt miten voimme toteuttaa saman hyödyntämällä JavaScriptin <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator\">array spread</a> ‑syntaksia:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">noteReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token operator\">:</span>\n<span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">return</span> <span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>state<span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">]</span></span>    <span class=\"token keyword\">case</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// ...</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n    <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Spread-syntaksi toimii seuraavasti. Jos määrittelemme</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> luvut <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token number\">3</span><span class=\"token punctuation\">]</span></code></pre></div>\n<p>niin <code>...luvut</code> hajottaa taulukon yksittäisiksi alkioiksi, eli voimme sijoittaa sen esim. toisen taulukon sisään:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>luvut<span class=\"token punctuation\">,</span> <span class=\"token number\">4</span><span class=\"token punctuation\">,</span> <span class=\"token number\">5</span><span class=\"token punctuation\">]</span></code></pre></div>\n<p>ja lopputuloksena on taulukko, jonka sisältö on <i>[1, 2, 3, 4, 5]</i>.</p>\n<p>Jos olisimme sijoittaneet taulukon toisen sisälle ilman spreadia, eli</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">[</span>luvut<span class=\"token punctuation\">,</span> <span class=\"token number\">4</span><span class=\"token punctuation\">,</span> <span class=\"token number\">5</span><span class=\"token punctuation\">]</span></code></pre></div>\n<p>lopputulos olisi ollut <i>[[1, 2, 3], 4, 5]</i>.</p>\n<p>Samannäköinen syntaksi toimii taulukosta <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\">destrukturoimalla</a> alkioita otettaessa siten, että se <i>kerää</i> loput alkiot:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> luvut <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span> <span class=\"token number\">4</span><span class=\"token punctuation\">,</span> <span class=\"token number\">5</span><span class=\"token punctuation\">,</span> <span class=\"token number\">6</span><span class=\"token punctuation\">]</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>eka<span class=\"token punctuation\">,</span> toka<span class=\"token punctuation\">,</span> <span class=\"token operator\">...</span>loput<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> luvut\n\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>eka<span class=\"token punctuation\">)</span>    <span class=\"token comment\">// tulostuu 1</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>toka<span class=\"token punctuation\">)</span>   <span class=\"token comment\">// tulostuu 2</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>loput<span class=\"token punctuation\">)</span>  <span class=\"token comment\">// tulostuu [3, 4, 5, 6]</span></code></pre></div>\n</div>\n<div class=\"tasks\">\n<h3>Tehtävät 6.1.-6.2.</h3>\n<p>Tehdään hieman yksinkertaistettu versio osan 1 Unicafe-tehtävästä. Hoidetaan sovelluksen tilan käsittely Reduxin avulla.</p>\n<p>Voit ottaa sovelluksesi pohjaksi repositoriossa <a href=\"https://github.com/fullstack-hy2020/unicafe-redux\">https://github.com/fullstack-hy2020/unicafe-redux</a> olevan projektin.</p>\n<p><i>Aloita poistamalla kloonatun sovelluksen Git-konfiguraatio ja asentamalla riippuvuudet:</i></p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> unicafe-redux   // mene kloonatun repositorion hakemistoon\n<span class=\"token function\">rm</span> <span class=\"token parameter variable\">-rf</span> .git\n<span class=\"token function\">npm</span> <span class=\"token function\">install</span></code></pre></div>\n<h4>6.1: Unicafe revisited, step1</h4>\n<p>Ennen sivulla näkyvää toiminnallisuutta toteutetaan storen edellyttämä toiminnallisuus.</p>\n<p>Storeen täytyy tallettaa erikseen lukumäärä jokaisentyyppisestä palautteesta. Storen hallitsema tila on siis muotoa:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">good</span><span class=\"token operator\">:</span> <span class=\"token number\">5</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">ok</span><span class=\"token operator\">:</span> <span class=\"token number\">4</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">bad</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Projektissa on seuraava runko reducerille:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> initialState <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">good</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">ok</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">bad</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">counterReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> initialState<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'GOOD'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'OK'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'BAD'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'RESET'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> counterReducer</code></pre></div>\n<p>Testien runko on:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> deepFreeze <span class=\"token keyword\">from</span> <span class=\"token string\">'deep-freeze'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> describe<span class=\"token punctuation\">,</span> expect<span class=\"token punctuation\">,</span> test <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'vitest'</span>\n<span class=\"token keyword\">import</span> counterReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducer'</span>\n\n<span class=\"token function\">describe</span><span class=\"token punctuation\">(</span><span class=\"token string\">'unicafe reducer'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> initialState <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">good</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">ok</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">bad</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token string\">'should return a proper initial state when called with undefined state'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> action <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'DO_NOTHING'</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">const</span> newState <span class=\"token operator\">=</span> <span class=\"token function\">counterReducer</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">undefined</span><span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">)</span>\n    <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toEqual</span><span class=\"token punctuation\">(</span>initialState<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token string\">'good is incremented'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> action <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'GOOD'</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">const</span> state <span class=\"token operator\">=</span> initialState\n\n    <span class=\"token function\">deepFreeze</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">const</span> newState <span class=\"token operator\">=</span> <span class=\"token function\">counterReducer</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">)</span>\n    <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toEqual</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">good</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">ok</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">bad</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><strong>Toteuta reducer ja tee sille testit.</strong></p>\n<p>Valmiina olevan ensimmäisen testin pitäisi mennä suoraan läpi ilman muutoksia. Redux olettaa, että reducer palauttaa järkevän alkutilan kun sitä kutsutaan siten että ensimmäinen parametri eli aiempaa tilaa edustava <i>state</i> on <i>undefined</i>.</p>\n<p>Aloita laajentamalla reduceria siten, että molemmat testeistä menevät läpi. Lisää tämän jälkeen loput testit reducerin eri actioneille ja toteuta niitä vastaava toiminnallisuus reduceriin.</p>\n<p>Varmista testeissä <i>deep-freeze</i>-kirjaston avulla, että kyseessä on <i>puhdas funktio</i>. Reducerin toteutuksessa kannattaa ottaa mallia yllä olevasta <a href=\"/osa6/flux_arkkitehtuuri_ja_redux#puhtaat-funktiot-immutable\">Redux-muistiinpanot</a>-esimerkistä.</p>\n<h4>6.2: Unicafe revisited, step2</h4>\n<p>Toteuta sitten sovellukseen koko sen varsinainen toiminnallisuus. </p>\n<p>Sovelluksesi saa olla ulkoasultaan vaatimaton, muuta ei tarvita kuin napit ja tieto kunkin tyyppisen arvostelun lukumäärästä: </p>\n<picture><img src=\"/static/f3e72d9a63da63ce780e21d8f249597a/5a190/50new.png\" srcset=\"/static/f3e72d9a63da63ce780e21d8f249597a/772e8/50new.png 200w,\n/static/f3e72d9a63da63ce780e21d8f249597a/e17e5/50new.png 400w,\n/static/f3e72d9a63da63ce780e21d8f249597a/5a190/50new.png 800w,\n/static/f3e72d9a63da63ce780e21d8f249597a/7bf07/50new.png 1128w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n</div>\n<div class=\"content\">\n<h3>Ei-kontrolloitu lomake</h3>\n<p>Lisätään sovellukseen mahdollisuus uusien muistiinpanojen tekemiseen sekä tärkeyden muuttamiseen:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// ...</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">generateId</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">Number</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>Math<span class=\"token punctuation\">.</span><span class=\"token function\">random</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toFixed</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">addNote</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">event</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value</span><span class=\"gatsby-highlight-code-line\">    event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value <span class=\"token operator\">=</span> <span class=\"token string\">''</span></span><span class=\"gatsby-highlight-code-line\">    store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">        content<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token function\">generateId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span></span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">toggleImportance</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">id</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> id <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span></span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">&lt;</span>form onSubmit<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>addNote<span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">&lt;</span>input name<span class=\"token operator\">=</span><span class=\"token string\">\"note\"</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span> </span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">&lt;</span>button type<span class=\"token operator\">=</span><span class=\"token string\">\"submit\"</span><span class=\"token operator\">></span>add<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span></span>      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n<span class=\"gatsby-highlight-code-line\">          <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span> onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">toggleImportance</span><span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span>            <span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span> <span class=\"token operator\">&lt;</span>strong<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>important <span class=\"token operator\">?</span> <span class=\"token string\">'important'</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>strong<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// ...</span></code></pre></div>\n<p>Molemmat toiminnallisuudet on toteutettu suoraviivaisesti. Huomionarvoista uuden muistiinpanon lisäämisessä on nyt se, että toisin kuin aiemmat Reactilla toteutetut lomakkeet, <i>emme ole</i> nyt sitoneet lomakkeen kentän arvoa komponentin <i>App</i> tilaan. React kutsuu tällaisia lomakkeita <a href=\"https://reactjs.org/docs/uncontrolled-components.html\">ei-kontrolloiduiksi</a>.</p>\n<blockquote>\n<p>Ei-kontrolloiduilla lomakkeilla on tiettyjä rajoitteita. Ne eivät mahdollista esim. lennossa annettavia validointiviestejä, lomakkeen lähetysnapin disabloimista sisällön perusteella yms. Meidän käyttötapaukseemme ne kuitenkin tällä kertaa sopivat.\nVoit halutessasi lukea aiheesta enemmän <a href=\"https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/\">täältä</a>.</p>\n</blockquote>\n<p>Muistiinpanon lisäämisen käsittelevä metodi on yksinkertainen. Se dispatchaa muistiinpanon lisäävän actionin:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function-variable function\">addNote</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">event</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value\n  event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value <span class=\"token operator\">=</span> <span class=\"token string\">''</span>\n<span class=\"gatsby-highlight-code-line\">  store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      content<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token function\">generateId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"token punctuation\">}</span></code></pre></div>\n<p>Uuden muistiinpanon sisältö saadaan suoraan lomakkeen syötekentästä, johon päästään käsiksi tapahtumaolion kautta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value</code></pre></div>\n<p>Kannattaa huomata, että syötekentällä on oltava nimi, jotta sen arvoon on mahdollista päästä käsiksi:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token operator\">&lt;</span>form onSubmit<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>addNote<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token operator\">&lt;</span>input name<span class=\"token operator\">=</span><span class=\"token string\">\"note\"</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span></span>  <span class=\"token operator\">&lt;</span>button type<span class=\"token operator\">=</span><span class=\"token string\">\"submit\"</span><span class=\"token operator\">></span>add<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span></code></pre></div>\n<p>Tärkeys muutetaan klikkaamalla muistiinpanon nimeä. Käsittelijä on erittäin yksinkertainen:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function-variable function\">toggleImportance</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">id</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> id <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3>Action creatorit</h3>\n<p>Alamme huomata, että jo näinkin yksinkertaisessa sovelluksessa Reduxin käyttö yksinkertaistaa sovelluksen ulkoasusta vastaavaa koodia. Pystymme kuitenkin vielä paljon parempaan. </p>\n<p>React-komponenttien on oikeastaan tarpeetonta tuntea Reduxin actionien tyyppejä ja esitysmuotoja. Eristetään actioneiden luominen omiin funktioihinsa:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">createNote</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">content</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      content<span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token function\">generateId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">toggleImportanceOf</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">id</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> id <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Actioneja luovia funktioita kutsutaan <a href=\"https://read.reduxbook.com/markdown/part1/04-action-creators.html\">action creatoreiksi</a>.</p>\n<p>Komponentin <i>App</i> ei tarvitse enää tietää mitään actionien sisäisestä esitystavasta, vaan se saa sopivan actionin kutsumalla creator-funktiota:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">addNote</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">event</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value\n    event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value <span class=\"token operator\">=</span> <span class=\"token string\">''</span>\n<span class=\"gatsby-highlight-code-line\">    store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">toggleImportance</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">id</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3>Redux-storen välittäminen eri komponenteille</h3>\n<p>Koko sovellus on toistaiseksi kirjoitettu reduceria lukuunottamatta yhteen tiedostoon, minkä ansiosta joka puolelta sovellusta on päästy käsiksi Redux-storeen. Entä jos haluamme jakaa sovelluksen useisiin, omiin tiedostoihinsa sijoitettuihin komponentteihin? </p>\n<p>Tapoja välittää Redux-store sovelluksen komponenteille on useita. Tutustutaan ensin ehkä uusimpaan ja helpoimpaan tapaan eli <a href=\"https://react-redux.js.org/\">React Redux</a>-kirjaston tarjoamaan <a href=\"https://react-redux.js.org/api/hooks\">hooks</a>-rajapintaan.</p>\n<p>Asennetaan react-redux:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> react-redux</code></pre></div>\n<p>Jäsennellään samalla sovelluksen koodi järkevämmin useisiin eri tiedostoihin. Tiedosto <em>main.jsx</em> näyttää muutosten jälkeen seuraavalta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom/client'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'redux'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Provider <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n\n<span class=\"token keyword\">import</span> App <span class=\"token keyword\">from</span> <span class=\"token string\">'./App'</span>\n<span class=\"token keyword\">import</span> noteReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span>\n\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>noteReducer<span class=\"token punctuation\">)</span>\n\nReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">createRoot</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'root'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span>Provider store<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>App <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Provider<span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Uutta tässä on se, että sovellus on määritelty React Redux ‑kirjaston tarjoaman <a href=\"https://react-redux.js.org/api/provider\">Provider</a>-komponentin lapsena ja että sovelluksen käyttämä store on annettu Provider-komponentin attribuutiksi <i>store</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>noteReducer<span class=\"token punctuation\">)</span>\n\nReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">createRoot</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'root'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token operator\">&lt;</span>Provider store<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span>    <span class=\"token operator\">&lt;</span>App <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Provider<span class=\"token operator\">></span></span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Tämän ansiosta <i>store</i> on kaikkien ohjelman komponenttien saavutettavissa, kuten tulemme pian näkemään.</p>\n<p>Action creator ‑funktioiden määrittely on siirretty reducerin kanssa samaan tiedostoon <i>src/reducers/noteReducer.js</i>, joka näyttää seuraavalta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">noteReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> <span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>state<span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">]</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> id <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">.</span>id\n      <span class=\"token keyword\">const</span> noteToChange <span class=\"token operator\">=</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">n</span> <span class=\"token operator\">=></span> n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> id<span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> changedNote <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">...</span>noteToChange<span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>noteToChange<span class=\"token punctuation\">.</span>important\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id <span class=\"token operator\">?</span> note <span class=\"token operator\">:</span> changedNote<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">generateId</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span>\n  <span class=\"token function\">Number</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>Math<span class=\"token punctuation\">.</span><span class=\"token function\">random</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toFixed</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">createNote</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">content</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'NEW_NOTE'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      content<span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token function\">generateId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">toggleImportanceOf</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> id <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> noteReducer</code></pre></div>\n<p>Moduulissa on nyt useita <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export\">export</a>-komentoja. Reducer-funktio palautetaan edelleen komennolla <i>export default</i>. Tämän ansiosta reducer importataan tuttuun tapaan:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> noteReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span></code></pre></div>\n<p>Moduulilla voi olla vain <i>yksi default export</i>, mutta useita \"normaaleja\" exporteja:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">createNote</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">content</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">toggleImportanceOf</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span> \n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Normaalisti (eli ei defaultina) exportattujen funktioiden käyttöönotto tapahtuu aaltosulkusyntaksilla:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createNote <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./../reducers/noteReducer'</span></code></pre></div>\n<p>Eriytetään seuraavaksi komponentti <em>App</em> tiedostoon <em>src/App.jsx</em>. Tiedoston sisältö on seuraava:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createNote<span class=\"token punctuation\">,</span> toggleImportanceOf <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useSelector<span class=\"token punctuation\">,</span> useDispatch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span> \n\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">addNote</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value\n    event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value <span class=\"token operator\">=</span> <span class=\"token string\">''</span>\n    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">toggleImportance</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>form onSubmit<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>addNote<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>input name<span class=\"token operator\">=</span><span class=\"token string\">\"note\"</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span> \n        <span class=\"token operator\">&lt;</span>button type<span class=\"token operator\">=</span><span class=\"token string\">\"submit\"</span><span class=\"token operator\">></span>add<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> \n          <span class=\"token operator\">&lt;</span>li\n            key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span> \n            onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">toggleImportance</span><span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n          <span class=\"token operator\">></span>\n            <span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span> <span class=\"token operator\">&lt;</span>strong<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>important <span class=\"token operator\">?</span> <span class=\"token string\">'important'</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>strong<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> App</code></pre></div>\n<p>Komponentin koodissa on muutama mielenkiintoinen seikka. Aiemmin koodi hoiti actionien dispatchaamisen kutsumalla Redux-storen metodia dispatch:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'TOGGLE_IMPORTANCE'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> id <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Nyt sama tapahtuu <a href=\"https://react-redux.js.org/api/hooks#usedispatch\">useDispatch</a>-hookin avulla saatavan <i>dispatch</i>-funktion avulla:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useSelector<span class=\"token punctuation\">,</span> useDispatch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span>  <span class=\"token comment\">// ...</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">toggleImportance</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>React Redux ‑kirjaston tarjoama <i>useDispatch</i>-hook siis tarjoaa mille tahansa React-komponentille pääsyn tiedostossa <i>main.jsx</i> määritellyn Redux-storen dispatch-funktioon, jonka avulla komponentti pääsee tekemään muutoksia Redux-storen tilaan.</p>\n<p>Storeen talletettuihin muistiinpanoihin komponentti pääsee käsiksi React Redux ‑kirjaston <a href=\"https://react-redux.js.org/api/hooks#useselector\">useSelector</a>-hookin kautta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useSelector<span class=\"token punctuation\">,</span> useDispatch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// ...</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">)</span></span>  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><i>useSelector</i> saa parametrikseen funktion, joka hakee tai valitsee (engl. select) tarvittavan datan Redux-storesta. Tarvitsemme nyt kaikki muistiinpanot, eli selektorifunktiomme palauttaa koko staten, eli on muotoa:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state</code></pre></div>\n<p>joka siis tarkoittaa samaa kuin</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> state\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Yleensä selektorifunktiot ovat mielenkiintoisempia ja valitsevat vain osan Redux-storen sisällöstä. Voisimme esimerkiksi hakea storesta ainoastaan tärkeät muistiinpanot seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> importantNotes <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> note<span class=\"token punctuation\">.</span>important<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>  </code></pre></div>\n<p>Redux-sovelluksen tämänhetkinen koodi on kokonaisuudessaan <a href=\"https://github.com/fullstack-hy2020/redux-notes/tree/part6-0\">GitHubissa</a>, branchissa <i>part6-0</i>.</p>\n<h3>Lisää komponentteja</h3>\n<p>Eriytetään uuden muistiinpanon luomisesta vastaava lomake omaksi komponentikseen tiedostoon <i>src/components/NoteForm.jsx</i>: </p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useDispatch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createNote <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'../reducers/noteReducer'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">NoteForm</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">addNote</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value\n    event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value <span class=\"token operator\">=</span> <span class=\"token string\">''</span>\n    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>form onSubmit<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>addNote<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input name<span class=\"token operator\">=</span><span class=\"token string\">\"note\"</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button type<span class=\"token operator\">=</span><span class=\"token string\">\"submit\"</span><span class=\"token operator\">></span>add<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> NoteForm</code></pre></div>\n<p>Toisin kuin aiemmin ilman Reduxia tekemässämme React-koodissa, sovelluksen tilaa (joka on nyt siis Reduxissa) muuttava tapahtumankäsittelijä on siirretty pois <i>App</i>-komponentista, alikomponentin vastuulle. Itse tilaa muuttava logiikka on kuitenkin siististi Reduxissa eristettynä koko sovelluksen React-osuudesta.</p>\n<p>Eriytetään vielä muistiinpanojen lista ja yksittäisen muistiinpanon esittäminen omiksi komponenteikseen. Sijoitetaan molemmat tiedostoon <i>src/components/Notes.jsx</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useDispatch<span class=\"token punctuation\">,</span> useSelector <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> toggleImportanceOf <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'../reducers/noteReducer'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Note</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> note<span class=\"token punctuation\">,</span> handleClick <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>li onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>handleClick<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>strong<span class=\"token operator\">></span> <span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>important <span class=\"token operator\">?</span> <span class=\"token string\">'important'</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>strong<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Notes</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>Note\n          key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span>\n          note<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">}</span>\n          handleClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> Notes</code></pre></div>\n<p>Muistiinpanon tärkeyttä muuttava logiikka on nyt muistiinpanojen listaa hallinnoivalla komponentilla.</p>\n<p>Tiedostoon <i>App.jsx</i> jää vain vähän koodia:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> NoteForm <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/NoteForm'</span>\n<span class=\"token keyword\">import</span> Notes <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/Notes'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>NoteForm <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>Notes <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> App</code></pre></div>\n<p>Yksittäisen muistiinpanon renderöinnistä huolehtiva <i>Note</i> on erittäin yksinkertainen, eikä ole tietoinen siitä, että sen propsina saama tapahtumankäsittelijä dispatchaa actionin. Tällaisia komponentteja kutsutaan Reactin terminologiassa <a href=\"https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0\">presentational</a>-komponenteiksi.</p>\n<p><i>Notes</i> taas on sellainen komponentti, jota kutsutaan <a href=\"https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0\">container</a>-komponentiksi. Se sisältää sovelluslogiikkaa eli määrittelee mitä <i>Note</i>-komponenttien tapahtumankäsittelijät tekevät ja koordinoi <i>presentational</i>-komponenttien eli <i>Notejen</i> konfigurointia.</p>\n<p>Palaamme presentational/container-jakoon tarkemmin myöhemmin tässä osassa.</p>\n<p>Redux-sovelluksen tämänhetkinen koodi on kokonaisuudessaan <a href=\"https://github.com/fullstack-hy2020/redux-notes/tree/part6-1\">GitHubissa</a>, branchissa <i>part6-1</i>.</p>\n</div>\n<div class=\"tasks\">\n<h3>Tehtävät 6.3.-6.8.</h3>\n<p>Toteutetaan nyt uusi versio ensimmäisen osan anekdoottien äänestyssovelluksesta. Ota ratkaisusi pohjaksi repositoriossa <a href=\"https://github.com/fullstack-hy2020/redux-anecdotes\">https://github.com/fullstack-hy2020/redux-anecdotes</a> oleva projekti.</p>\n<p>Jos kloonaat projektin olemassaolevan Git-repositorion sisälle, <i>poista kloonatun sovelluksen Git-konfiguraatio:</i></p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> redux-anecdotes  // mene kloonatun repositorion hakemistoon\n<span class=\"token function\">rm</span> <span class=\"token parameter variable\">-rf</span> .git</code></pre></div>\n<p>Sovellus käynnistyy normaaliin tapaan, mutta joudut ensin asentamaan sen riippuvuudet:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span>\n<span class=\"token function\">npm</span> run dev</code></pre></div>\n<p>Kun teet seuraavat tehtävät, tulisi sovelluksen näyttää seuraavalta:</p>\n<picture><img src=\"/static/3355cef5793e5407ab7fc33e79195749/5a190/3.png\" alt=\"Sovellus renderöi anekdootit. Jokaisen anekdootin yhteydessä myös tieto sen saamien äänien määrästä sekä nappi &#x22;vote&#x22; anekdootin äänestämiselle\" srcset=\"/static/3355cef5793e5407ab7fc33e79195749/772e8/3.png 200w,\n/static/3355cef5793e5407ab7fc33e79195749/e17e5/3.png 400w,\n/static/3355cef5793e5407ab7fc33e79195749/5a190/3.png 800w,\n/static/3355cef5793e5407ab7fc33e79195749/c1b63/3.png 1200w,\n/static/3355cef5793e5407ab7fc33e79195749/61946/3.png 1546w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<h4>6.3: anekdootit, step1</h4>\n<p>Toteuta mahdollisuus anekdoottien äänestämiseen. Äänien määrä tulee tallettaa Redux-storeen.</p>\n<h4>6.4: anekdootit, step2</h4>\n<p>Tee sovellukseen mahdollisuus uusien anekdoottien lisäämiselle.</p>\n<p>Voit pitää lisäyslomakkeen aiemman esimerkin tapaan <a href=\"/osa6/flux_arkkitehtuuri_ja_redux#ei-kontrolloitu-lomake\">ei-kontrolloituna</a>.</p>\n<h4>6.5: anekdootit, step3</h4>\n<p>Huolehdi siitä, että anekdootit pysyvät äänten mukaisessa suuruusjärjestyksessä.</p>\n<h4>6.6: anekdootit, step4</h4>\n<p>Jos et jo sitä tehnyt, eriytä action-olioiden luominen <a href=\"https://redux.js.org/basics/actions#action-creators\">action creator</a> ‑funktioihin ja sijoita ne tiedostoon <i>src/reducers/anecdoteReducer.js</i>. Toimi siis kuten materiaalin esimerkissä on toimittu kohdasta <a href=\"/osa6/flux_arkkitehtuuri_ja_redux#action-creatorit\">action creator</a> alkaen.</p>\n<h4>6.7: anekdootit, step5</h4>\n<p>Eriytä uuden anekdootin luominen omaksi komponentikseen nimeltään <i>AnecdoteForm</i>. Siirrä kaikki anekdootin luomiseen liittyvä logiikka uuteen komponenttiin.</p>\n<h4>6.8: anekdootit, step6</h4>\n<p>Eriytä anekdoottilistan näyttäminen omaksi komponentikseen nimeltään <i>AnecdoteList</i>. Siirrä kaikki anekdoottien äänestämiseen liittyvä logiikka uuteen komponenttiin.</p>\n<p>Tämän tehtävän jälkeen komponentin <i>App</i> pitäisi näyttää seuraavalta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> AnecdoteForm <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/AnecdoteForm'</span>\n<span class=\"token keyword\">import</span> AnecdoteList <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/AnecdoteList'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>h2<span class=\"token operator\">></span>Anecdotes<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h2<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>AnecdoteForm <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>AnecdoteList <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> App</code></pre></div>\n</div>\n<div class=\"content\">\n<p>Jatketaan muistiinpanosovelluksen yksinkertaistetun <a href=\"/osa6/flux_arkkitehtuuri_ja_redux#redux-muistiinpanot\">Redux-version</a> laajentamista.</p>\n<p>Sovelluskehitystä helpottaaksemme laajennetaan reduceria siten, että storelle määritellään alkutila, jossa on pari muistiinpanoa:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> initialState <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'reducer defines how redux store works'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'state of store can contain any data'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">]</span></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">noteReducer</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">state <span class=\"token operator\">=</span> initialState<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span>  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// ...</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> noteReducer</code></pre></div>\n<h3>Monimutkaisempi tila storessa</h3>\n<p>Toteutetaan sovellukseen näytettävien muistiinpanojen filtteröinti, jonka avulla näytettäviä muistiinpanoja voidaan rajata. Filtterin toteutus tapahtuu <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio\">radiopainikkeiden</a> avulla:</p>\n<picture><img src=\"/static/19f400b0638887ff6a81b5f071c59e44/5a190/01f.png\" alt=\"Sivun alussa lomake muistiinpanon lisäämiseen (syötekenttä ja nappi add). Tämän jälkeen radiopainikevalinta mitkä muistiinpanot näytetään, vaihtoehdot all, important ja noimportant. Näiden alle renderöidän kaikki muistiinpanot ja niiden yhteyteen teksti important jos muistiinpano merkattu tärkeäksi. \" srcset=\"/static/19f400b0638887ff6a81b5f071c59e44/772e8/01f.png 200w,\n/static/19f400b0638887ff6a81b5f071c59e44/e17e5/01f.png 400w,\n/static/19f400b0638887ff6a81b5f071c59e44/5a190/01f.png 800w,\n/static/19f400b0638887ff6a81b5f071c59e44/38124/01f.png 953w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Aloitetaan todella suoraviivaisella toteutuksella:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> NoteForm <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/NoteForm'</span>\n<span class=\"token keyword\">import</span> Notes <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/Notes'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">filterSelected</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">value</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>value<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span></span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>NoteForm <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">&lt;</span>input</span><span class=\"gatsby-highlight-code-line\">          type<span class=\"token operator\">=</span><span class=\"token string\">\"radio\"</span></span><span class=\"gatsby-highlight-code-line\">          name<span class=\"token operator\">=</span><span class=\"token string\">\"filter\"</span></span><span class=\"gatsby-highlight-code-line\">          onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">filterSelected</span><span class=\"token punctuation\">(</span><span class=\"token string\">'ALL'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">/</span><span class=\"token operator\">></span></span><span class=\"gatsby-highlight-code-line\">        all</span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">&lt;</span>input</span><span class=\"gatsby-highlight-code-line\">          type<span class=\"token operator\">=</span><span class=\"token string\">\"radio\"</span></span><span class=\"gatsby-highlight-code-line\">          name<span class=\"token operator\">=</span><span class=\"token string\">\"filter\"</span></span><span class=\"gatsby-highlight-code-line\">          onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">filterSelected</span><span class=\"token punctuation\">(</span><span class=\"token string\">'IMPORTANT'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">/</span><span class=\"token operator\">></span></span><span class=\"gatsby-highlight-code-line\">        important</span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">&lt;</span>input</span><span class=\"gatsby-highlight-code-line\">          type<span class=\"token operator\">=</span><span class=\"token string\">\"radio\"</span></span><span class=\"gatsby-highlight-code-line\">          name<span class=\"token operator\">=</span><span class=\"token string\">\"filter\"</span></span><span class=\"gatsby-highlight-code-line\">          onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">filterSelected</span><span class=\"token punctuation\">(</span><span class=\"token string\">'NONIMPORTANT'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">/</span><span class=\"token operator\">></span></span><span class=\"gatsby-highlight-code-line\">        nonimportant</span><span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span></span>      <span class=\"token operator\">&lt;</span>Notes <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Koska painikkeiden attribuutin <i>name</i> arvo on kaikilla sama, muodostavat ne <i>nappiryhmän</i>, joista ainoastaan yksi voi olla kerrallaan valittuna.</p>\n<p>Napeille on määritelty muutoksenkäsittelijä, joka tällä hetkellä ainoastaan tulostaa painettua nappia vastaavan merkkijonon konsoliin.</p>\n<p>Päätämme toteuttaa filtteröinnin siten, että talletamme muistiinpanojen lisäksi sovelluksen storeen myös <i>filtterin arvon</i>. Eli muutoksen jälkeen storessa olevan tilan tulisi näyttää seuraavalta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'reducer defines how redux store works'</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'state of store can contain any data'</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">filter</span><span class=\"token operator\">:</span> <span class=\"token string\">'IMPORTANT'</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Tällä hetkellähän tilassa on ainoastaan muistiinpanot sisältävä taulukko. Uudessa ratkaisussa tilalla on siis kaksi avainta eli <i>notes</i>, jonka arvona muistiinpanot ovat sekä <i>filter</i>, jonka arvona on merkkijono joka kertoo, mitkä muistiinpanoista tulisi näyttää ruudulla.</p>\n<h3>Yhdistetyt reducerit</h3>\n<p>Voisimme periaatteessa muokata jo olemassaolevaa reduceria ottamaan huomioon muuttuneen tilanteen. Parempi ratkaisu on kuitenkin määritellä tässä tilanteessa uusi, filtterin arvosta huolehtiva reduceri. Määritellään samalla myös sopiva <em>action creator</em> ‑funktio. Sijoitetaan koodi moduuliin <i>src/reducers/filterReducer.js</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> filterReducer <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>state <span class=\"token operator\">=</span> <span class=\"token string\">'ALL'</span><span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">'SET_FILTER'</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> action<span class=\"token punctuation\">.</span>payload\n    <span class=\"token keyword\">default</span><span class=\"token operator\">:</span>\n      <span class=\"token keyword\">return</span> state\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">filterChange</span> <span class=\"token operator\">=</span> <span class=\"token parameter\">filter</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'SET_FILTER'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> filter\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> filterReducer</code></pre></div>\n<p>Filtterin arvon asettavat actionit ovat siis muotoa:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'SET_FILTER'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token string\">'IMPORTANT'</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Saamme nyt muodostettua varsinaisen reducerin yhdistämällä kaksi olemassaolevaa reduceria funktion <a href=\"https://redux.js.org/api/combinereducers\">combineReducers</a> avulla.</p>\n<p>Määritellään yhdistetty reducer tiedostossa <i>main.jsx</i>. Tiedoston päivitetty sisältö on seuraavanlainen:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom/client'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Provider <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createStore<span class=\"token punctuation\">,</span> combineReducers <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'redux'</span>\n\n<span class=\"token keyword\">import</span> App <span class=\"token keyword\">from</span> <span class=\"token string\">'./App'</span>\n<span class=\"token keyword\">import</span> filterReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/filterReducer'</span>\n<span class=\"token keyword\">import</span> noteReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span>\n\n<span class=\"token keyword\">const</span> reducer <span class=\"token operator\">=</span> <span class=\"token function\">combineReducers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> noteReducer<span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">filter</span><span class=\"token operator\">:</span> filterReducer\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>reducer<span class=\"token punctuation\">)</span>\n\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\nReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">createRoot</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'root'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span>Provider store<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>div <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Provider<span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Koska sovelluksemme hajoaa tässä vaiheessa täysin, komponentin <i>App</i> sijasta renderöidään tyhjä <i>div</i>-elementti.</p>\n<p><em>console.log</em>-komennon ansiosta konsoliin tulostuu storen tila:</p>\n<picture><img src=\"/static/1b0877b46c22965801911f30d5bb233d/5a190/4e.png\" alt=\"Konsolista selviää että store on olio jolla kentät filter (teksti, arvona &#x22;ALL&#x22;) ja notes (taulukollinen muistiinpanoja).\" srcset=\"/static/1b0877b46c22965801911f30d5bb233d/772e8/4e.png 200w,\n/static/1b0877b46c22965801911f30d5bb233d/e17e5/4e.png 400w,\n/static/1b0877b46c22965801911f30d5bb233d/5a190/4e.png 800w,\n/static/1b0877b46c22965801911f30d5bb233d/c1b63/4e.png 1200w,\n/static/1b0877b46c22965801911f30d5bb233d/08c33/4e.png 1570w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Store on siis juuri siinä muodossa jossa haluammekin sen olevan!</p>\n<p>Tarkastellaan vielä yhdistetyn reducerin luomista:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> reducer <span class=\"token operator\">=</span> <span class=\"token function\">combineReducers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> noteReducer<span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">filter</span><span class=\"token operator\">:</span> filterReducer<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Näin tehdyn reducerin määrittelemän storen tila on olio, jossa on kaksi kenttää: <i>notes</i> ja <i>filter</i>. Tilan kentän <i>notes</i> arvon määrittelee <i>noteReducer</i>, jonka ei tarvitse välittää mitään tilan muista kentistä. Vastaavasti <i>filter</i> kentän käsittely tapahtuu <i>filterReducer</i>:in avulla.</p>\n<p>Ennen muun koodin muutoksia kokeillaan vielä konsolista, miten actionit muuttavat yhdistetyn reducerin muodostamaa staten tilaa. Lisätään seuraavat rivit väliaikaisesti tiedostoon <i>main.jsx</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// ...</span>\n\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>reducer<span class=\"token punctuation\">)</span>\n\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createNote <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> filterChange <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/filterReducer'</span></span>\n<span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">subscribe</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">filterChange</span><span class=\"token punctuation\">(</span><span class=\"token string\">'IMPORTANT'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">store<span class=\"token punctuation\">.</span><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span><span class=\"token string\">'combineReducers forms one reducer from many simple reducers'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span>\nReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">createRoot</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'root'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span>Provider store<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>div <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Provider<span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Kun simuloimme näin filtterin tilan muutosta ja muistiinpanon luomista, konsoliin tulostuu storen tila jokaisen muutoksen jälkeen:</p>\n<picture><img src=\"/static/964dbbbda189dbdd44ab31ad309fc058/5a190/5e.png\" alt=\"Storen filter-arvoksi muuttuu ensin IMPORTANT, tämän jäleen storen notesiin tulee uusi muistiinpano\" srcset=\"/static/964dbbbda189dbdd44ab31ad309fc058/772e8/5e.png 200w,\n/static/964dbbbda189dbdd44ab31ad309fc058/e17e5/5e.png 400w,\n/static/964dbbbda189dbdd44ab31ad309fc058/5a190/5e.png 800w,\n/static/964dbbbda189dbdd44ab31ad309fc058/c1b63/5e.png 1200w,\n/static/964dbbbda189dbdd44ab31ad309fc058/29007/5e.png 1600w,\n/static/964dbbbda189dbdd44ab31ad309fc058/27f8b/5e.png 1730w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Jo tässä vaiheessa kannattaa laittaa mieleen eräs tärkeä detalji. Jos <i>molempien reducerien alkuun</i> lisätään konsoliin tulostus</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> filterReducer <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>state <span class=\"token operator\">=</span> <span class=\"token string\">'ALL'</span><span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'ACTION: '</span><span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">)</span></span>  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>niin nyt konsolin perusteella näyttää siltä, että jokainen action kahdentuu:</p>\n<picture><img src=\"/static/823e8c9b9d906019902ce11b2f24db56/5a190/6.png\" alt=\"Konsolin tulostus paljastaa että sekä noteReducer että filterReducer käsittelevät jokaisen actionin\" srcset=\"/static/823e8c9b9d906019902ce11b2f24db56/772e8/6.png 200w,\n/static/823e8c9b9d906019902ce11b2f24db56/e17e5/6.png 400w,\n/static/823e8c9b9d906019902ce11b2f24db56/5a190/6.png 800w,\n/static/823e8c9b9d906019902ce11b2f24db56/c1b63/6.png 1200w,\n/static/823e8c9b9d906019902ce11b2f24db56/29007/6.png 1600w,\n/static/823e8c9b9d906019902ce11b2f24db56/9eaa0/6.png 1676w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Onko koodissa bugi? Ei. Yhdistetty reducer toimii siten, että jokainen <i>action</i> käsitellään <i>kaikissa</i> yhdistetyn reducerin osissa. Usein tietystä actionista on kiinnostunut vain yksi reducer, mutta on kuitenkin tilanteita, joissa useampi reducer muuttaa hallitsemaansa staten tilaa jonkin actionin seurauksena.</p>\n<h3>Filtteröinnin viimeistely</h3>\n<p>Viimeistellään nyt sovellus käyttämään yhdistettyä reduceria. Poistetaan tiedostosta <i>main.jsx</i> ylimääräiset kokeilut ja palautetaan <em>App</em> renderöitäväksi komponentiksi. Tiedoston päivitetty sisältö on seuraava:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom/client'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Provider <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createStore<span class=\"token punctuation\">,</span> combineReducers <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'redux'</span>\n\n<span class=\"token keyword\">import</span> App <span class=\"token keyword\">from</span> <span class=\"token string\">'./App'</span>\n<span class=\"token keyword\">import</span> filterReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/filterReducer'</span>\n<span class=\"token keyword\">import</span> noteReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span>\n\n<span class=\"token keyword\">const</span> reducer <span class=\"token operator\">=</span> <span class=\"token function\">combineReducers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> noteReducer<span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">filter</span><span class=\"token operator\">:</span> filterReducer\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">createStore</span><span class=\"token punctuation\">(</span>reducer<span class=\"token punctuation\">)</span>\n\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\nReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">createRoot</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'root'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span>Provider store<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>App <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Provider<span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Korjataan sitten bugi, joka johtuu siitä, että koodi olettaa storen tilan olevan mustiinpanot tallettava taulukko:</p>\n<picture><img src=\"/static/d805000d48c52d3a6fdbe455393542f1/5a190/7v.png\" alt=\"komennon notes.map(note => ...) suoritus aiheuttaa virheen TypeError notes.map is not a function)\" srcset=\"/static/d805000d48c52d3a6fdbe455393542f1/772e8/7v.png 200w,\n/static/d805000d48c52d3a6fdbe455393542f1/e17e5/7v.png 400w,\n/static/d805000d48c52d3a6fdbe455393542f1/5a190/7v.png 800w,\n/static/d805000d48c52d3a6fdbe455393542f1/c1b63/7v.png 1200w,\n/static/d805000d48c52d3a6fdbe455393542f1/2a333/7v.png 1484w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Korjaus on helppo. Koska muistiinpanot ovat nyt storen kentässä <i>notes</i>, riittää pieni muutos selektorifunktioon:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Notes</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">)</span></span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span>\n        <span class=\"token operator\">&lt;</span>Note\n          key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span>\n          note<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">}</span>\n          handleClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> \n            <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Aiemminhan selektorifunktio palautti koko storen tilan:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Nyt siis palautetaan tilasta ainoastaan sen kenttä <i>notes</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Eriytetään näkyvyyden säätelyfiltteri omaksi, tiedostoon <i>src/components/VisibilityFilter.jsx</i> sijoitettavaksi komponentiksi:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useDispatch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> filterChange <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'../reducers/filterReducer'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">VisibilityFilter</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input\n        type<span class=\"token operator\">=</span><span class=\"token string\">\"radio\"</span>\n        name<span class=\"token operator\">=</span><span class=\"token string\">\"filter\"</span>\n        onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">filterChange</span><span class=\"token punctuation\">(</span><span class=\"token string\">'ALL'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      all\n      <span class=\"token operator\">&lt;</span>input\n        type<span class=\"token operator\">=</span><span class=\"token string\">\"radio\"</span>\n        name<span class=\"token operator\">=</span><span class=\"token string\">\"filter\"</span>\n        onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">filterChange</span><span class=\"token punctuation\">(</span><span class=\"token string\">'IMPORTANT'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      important\n      <span class=\"token operator\">&lt;</span>input\n        type<span class=\"token operator\">=</span><span class=\"token string\">\"radio\"</span>\n        name<span class=\"token operator\">=</span><span class=\"token string\">\"filter\"</span>\n        onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">filterChange</span><span class=\"token punctuation\">(</span><span class=\"token string\">'NONIMPORTANT'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      nonimportant\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> VisibilityFilter</code></pre></div>\n<p>Toteutus on suoraviivainen - radiopainikkeen klikkaaminen muuttaa storen kentän <i>filter</i> tilaa.</p>\n<p>Komponentti <i>App</i> yksinkertaisuu nyt seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> NoteForm <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/NoteForm'</span>\n<span class=\"token keyword\">import</span> Notes <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/Notes'</span>\n<span class=\"token keyword\">import</span> VisibilityFilter <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/VisibilityFilter'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>NoteForm <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>VisibilityFilter <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>Notes <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> App</code></pre></div>\n<p>Muutetaan vielä komponenttia <i>Notes</i> ottamaan huomioon filtteri:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Notes</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">.</span>filter <span class=\"token operator\">===</span> <span class=\"token string\">'ALL'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span>notes</span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span>filter <span class=\"token operator\">===</span> <span class=\"token string\">'IMPORTANT'</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">?</span> state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> note<span class=\"token punctuation\">.</span>important<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token operator\">!</span>note<span class=\"token punctuation\">.</span>important<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>Note\n          key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span>\n          note<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">}</span>\n          handleClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Muutos kohdistuu siis ainoastaan selektorifunktioon, joka oli aiemmin muotoa</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Yksinkertaistetaan vielä selektoria destrukturoimalla parametrina olevasta tilasta sen kentät erilleen:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useSelector</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> filter<span class=\"token punctuation\">,</span> notes <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span> filter <span class=\"token operator\">===</span> <span class=\"token string\">'ALL'</span> <span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> notes\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span> filter  <span class=\"token operator\">===</span> <span class=\"token string\">'IMPORTANT'</span> \n    <span class=\"token operator\">?</span> notes<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> note<span class=\"token punctuation\">.</span>important<span class=\"token punctuation\">)</span>\n    <span class=\"token operator\">:</span> notes<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token operator\">!</span>note<span class=\"token punctuation\">.</span>important<span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Sovelluksessa on vielä pieni kauneusvirhe, sillä vaikka oletusarvosesti filtterin arvo on <i>ALL</i> eli näytetään kaikki muistiinpanot, ei vastaava radiopainike ole valittuna. Ongelma on luonnollisestikin mahdollista korjata, mutta koska kyseessä on ikävä, mutta harmiton feature, jätämme korjauksen myöhemmäksi.</p>\n<p>Redux-sovelluksen tämänhetkinen koodi on kokonaisuudessaan <a href=\"https://github.com/fullstack-hy2020/redux-notes/tree/part6-2\">GitHubissa</a>, branchissa <i>part6-2</i>.</p>\n</div>\n<div class=\"tasks\">\n<h3>Tehtävä 6.9</h3>\n<p>Jatketaan tehtävässä 6.3 aloitetun Reduxia käyttävän anekdoottisovelluksen parissa.</p>\n<h4>6.9 anekdootit, step7</h4>\n<p>Toteuta sovellukseen näytettävien anekdoottien filtteröiminen:</p>\n<picture><img src=\"/static/e64e260dbd3b22669115b6eb9dcce7a5/5a190/9ea.png\" alt=\"Yläosaan lisätään tekstikenttä, johon kirjoittamalla voidaan rajoittaa näytettävät anekdootit niihin joihin sisältyy &#x22;filtterikenttään&#x22; kirjoitettu merkkijono\" srcset=\"/static/e64e260dbd3b22669115b6eb9dcce7a5/772e8/9ea.png 200w,\n/static/e64e260dbd3b22669115b6eb9dcce7a5/e17e5/9ea.png 400w,\n/static/e64e260dbd3b22669115b6eb9dcce7a5/5a190/9ea.png 800w,\n/static/e64e260dbd3b22669115b6eb9dcce7a5/c1b63/9ea.png 1200w,\n/static/e64e260dbd3b22669115b6eb9dcce7a5/29007/9ea.png 1600w,\n/static/e64e260dbd3b22669115b6eb9dcce7a5/5fada/9ea.png 1706w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Säilytä filtterin tila Redux-storessa. Käytännössä kannattaa tehdä uusi reducer ja action creatorit, ja luoda storea varten yhdistetty reduceri funktion <i>combineReducers</i> avulla.</p>\n<p>Tee filtterin ruudulla näyttämistä varten komponentti <i>Filter</i>. Voit ottaa sen pohjaksi seuraavan koodin:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Filter</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleChange</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// input-kentän arvo muuttujassa event.target.value</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">const</span> style <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">marginBottom</span><span class=\"token operator\">:</span> <span class=\"token number\">10</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div style<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>style<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      filter <span class=\"token operator\">&lt;</span>input onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>handleChange<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> Filter</code></pre></div>\n</div>\n<div class=\"content\">\n<h3>Redux Toolkit ja storen konfiguraation refaktorointi</h3>\n<p>Kuten olemme jo tähän asti huomanneet, Reduxin konfigurointi ja tilanhallinnan toteutus vaativat melko paljon vaivannäköä. Tämä ilmenee esimerkiksi reducereiden ja action creatorien koodista, jossa on jonkin verran toisteisuutta. <a href=\"https://redux-toolkit.js.org/\">Redux Toolkit</a> on kirjasto, joka soveltuu näiden yleisten Reduxin käyttöön liittyvien ongelmien ratkaisemiseen. Kirjaston käyttö mm. yksinkertaistaa huomattavasti Redux-storen luontia ja tarjoaa suuren määrän tilanhallintaa helpottavia työkaluja.</p>\n<p>Otetaan Redux Toolkit käyttöön sovelluksessamme refaktoroimalla nykyistä koodia. Aloitetaan kirjaston asennuksella:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">npm install @reduxjs/toolkit</code></pre></div>\n<p>Avataan sen jälkeen <i>main.jsx</i>-tiedosto, jossa nykyinen Redux-store luodaan. Käytetään storen luonnissa Reduxin <em>createStore</em>-funktion sijaan Redux Toolkitin <a href=\"https://redux-toolkit.js.org/api/configureStore\">configureStore</a>-funktiota:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom/client'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Provider <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> configureStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@reduxjs/toolkit'</span></span>\n<span class=\"token keyword\">import</span> App <span class=\"token keyword\">from</span> <span class=\"token string\">'./App'</span>\n<span class=\"token keyword\">import</span> filterReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/filterReducer'</span>\n<span class=\"token keyword\">import</span> noteReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">configureStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token literal-property property\">reducer</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> noteReducer<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">filter</span><span class=\"token operator\">:</span> filterReducer</span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>store<span class=\"token punctuation\">.</span><span class=\"token function\">getState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\nReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">createRoot</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'root'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span>Provider store<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>App <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Provider<span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Pääsimme eroon jo muutamasta koodirivistä, kun reducerin muodostamiseen ei enää tarvita <em>combineReducers</em>-funktiota. Tulemme pian näkemään, että <em>configureStore</em>-funktion käytöstä on myös monia muita hyötyjä, kuten kehitystyökalujen ja usein käytettyjen kirjastojen vaivaton käyttöönotto ilman erillistä konfiguraatiota.</p>\n<p>Siistitään vielä <i>main.jsx</i>-tiedostoa siirtämällä Redux-storen luontiin liittyvä koodi erilliseen tiedostoon. Luodaan uusi tiedosto <i>src/store.js</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> configureStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@reduxjs/toolkit'</span>\n\n<span class=\"token keyword\">import</span> noteReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span>\n<span class=\"token keyword\">import</span> filterReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/filterReducer'</span>\n\n<span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> <span class=\"token function\">configureStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">reducer</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> noteReducer<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">filter</span><span class=\"token operator\">:</span> filterReducer\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> store</code></pre></div>\n<p>Muutosten jälkeen <i>main.jsx</i>-tiedosto näyttää seuraavalta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> ReactDOM <span class=\"token keyword\">from</span> <span class=\"token string\">'react-dom/client'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Provider <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n\n<span class=\"token keyword\">import</span> App <span class=\"token keyword\">from</span> <span class=\"token string\">'./App'</span>\n<span class=\"token keyword\">import</span> store <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</span>\n\nReactDOM<span class=\"token punctuation\">.</span><span class=\"token function\">createRoot</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">'root'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">render</span><span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span>Provider store<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>store<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span>App <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n  <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Provider<span class=\"token operator\">></span>\n<span class=\"token punctuation\">)</span></code></pre></div>\n<h3>Redux Toolkit ja reducereiden refaktorointi</h3>\n<p>Siirrytään seuraavaksi reducereiden refaktorointiin, jossa Redux Toolkitin edut tulevat parhaiten esiin. Redux Toolkitin avulla reducerin ja siihen liittyvät action creatorit voi luoda kätevästi <a href=\"https://redux-toolkit.js.org/api/createSlice\">createSlice</a>-funktion avulla. Voimme refaktoroida <i>reducers/noteReducer.js</i>-tiedostossa olevan reducerin ja action creatorit <em>createSlice</em>-funktion avulla seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createSlice <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@reduxjs/toolkit'</span></span>\n<span class=\"token keyword\">const</span> initialState <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'reducer defines how redux store works'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'state of store can contain any data'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">]</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">generateId</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span>\n  <span class=\"token function\">Number</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>Math<span class=\"token punctuation\">.</span><span class=\"token function\">random</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toFixed</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> noteSlice <span class=\"token operator\">=</span> <span class=\"token function\">createSlice</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">  initialState<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token literal-property property\">reducers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload</span><span class=\"gatsby-highlight-code-line\"></span><span class=\"gatsby-highlight-code-line\">      state<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">        content<span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">        <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token function\">generateId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">const</span> id <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload</span><span class=\"gatsby-highlight-code-line\"></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">const</span> noteToChange <span class=\"token operator\">=</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">n</span> <span class=\"token operator\">=></span> n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> id<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\"></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">const</span> changedNote <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> </span><span class=\"gatsby-highlight-code-line\">        <span class=\"token operator\">...</span>noteToChange<span class=\"token punctuation\">,</span> </span><span class=\"gatsby-highlight-code-line\">        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>noteToChange<span class=\"token punctuation\">.</span>important </span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\"></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span></span><span class=\"gatsby-highlight-code-line\">        note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id <span class=\"token operator\">?</span> note <span class=\"token operator\">:</span> changedNote </span><span class=\"gatsby-highlight-code-line\">      <span class=\"token punctuation\">)</span>     </span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createNote<span class=\"token punctuation\">,</span> toggleImportanceOf <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> noteSlice<span class=\"token punctuation\">.</span>actions</span><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> noteSlice<span class=\"token punctuation\">.</span>reducer</span></code></pre></div>\n<p><em>createSlice</em>-funktion <em>name</em>-parametri määrittelee etuliitteen, jota käytetään actioneiden type-arvoissa. Esimerkiksi myöhemmin määritelty <em>createNote</em>-action saa type-arvon <em>notes/createNote</em>. Parametrin arvona on hyvä käyttää muiden reducereiden kesken uniikkia nimeä, jotta sovelluksen actioneiden type-arvoissa ei tapahtuisi odottamattomia yhteentörmäyksiä. Parametri <em>initialState</em> määrittelee reducerin alustavan tilan. Parametri <em>reducers</em> määrittelee itse reducerin objektina, jonka funktiot käsittelevät tietyn actionin aiheuttamat tilamuutokset. Huomaa, että funktioissa <em>action.payload</em> sisältää action creatorin kutsussa annetun parametrin:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Redux Toolkit is awesome!'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Tämä dispatch-kutsu vastaa seuraavan objektin dispatchaamista:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes/createNote'</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token string\">'Redux Toolkit is awesome!'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Jos olit tarkkana, saatoit huomata, että actionin <em>createNote</em> kohdalla tapahtuu jotain, mikä vaikuttaa rikkovan aiemmin mainittua reducereiden immutabiliteetin periaatetta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload\n\n  state<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    content<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token function\">generateId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Mutatoimme <em>state</em>-argumentin taulukkoa kutsumalla <em>push</em>-metodia sen sijaan, että palauttaisimme uuden instanssin taulukosta. Mistä on kyse?</p>\n<p>Redux Toolkit hyödyntää <em>createSlice</em>-funktion avulla määritellyissä reducereissa <a href=\"https://immerjs.github.io/immer/\">Immer</a>-kirjastoa, joka mahdollistaa <em>state</em>-argumentin mutatoinnin reducerin sisällä. Immer muodostaa mutatoidun tilan perusteella uuden, immutablen tilan ja näin tilamuutosten immutabiliteetti säilyy.</p>\n<p>Huomaa, että tilaa voi muuttaa myös \"mutatoimatta\" kuten esimerkiksi <em>toggleImportanceOf</em> ‑actionin kohdalla on tehty. Tällöin funktio palauttaa uuden tilan. Mutatointi osoittautuu kuitenkin usein hyödylliseksi etenkin rakenteeltaan monimutkaisen tilan päivittämisessä.</p>\n<p>Funktio <em>createSlice</em> palauttaa objektin, joka sisältää sekä reducerin että <em>reducers</em>-parametrin actioneiden mukaiset action creatorit. Reducer on palautetussa objektissa <em>noteSlice.reducer</em>-kentässä kun taas action creatorit ovat <em>noteSlice.actions</em>-kentässä. Voimme muodostaa tiedoston exportit kätevästi:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> noteSlice <span class=\"token operator\">=</span> <span class=\"token function\">createSlice</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createNote<span class=\"token punctuation\">,</span> toggleImportanceOf <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> noteSlice<span class=\"token punctuation\">.</span>actions</span><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> noteSlice<span class=\"token punctuation\">.</span>reducer</span></code></pre></div>\n<p>Importit toimivat muissa tiedostoissa tavalliseen tapaan:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> noteReducer<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> createNote<span class=\"token punctuation\">,</span> toggleImportanceOf <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span></code></pre></div>\n<p>Joudumme hieman muuttamaan testejämme Redux Toolkitin nimeämiskäytäntöjen takia:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> deepFreeze <span class=\"token keyword\">from</span> <span class=\"token string\">'deep-freeze'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> describe<span class=\"token punctuation\">,</span> expect<span class=\"token punctuation\">,</span> test <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'vitest'</span>\n<span class=\"token keyword\">import</span> noteReducer <span class=\"token keyword\">from</span> <span class=\"token string\">'./noteReducer'</span>\n\n<span class=\"token function\">describe</span><span class=\"token punctuation\">(</span><span class=\"token string\">'noteReducer'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token string\">'returns new state with action notes/createNote'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span>    <span class=\"token keyword\">const</span> state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span>\n    <span class=\"token keyword\">const</span> action <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes/createNote'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token string\">'the app state is in redux store'</span></span>    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token function\">deepFreeze</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">const</span> newState <span class=\"token operator\">=</span> <span class=\"token function\">noteReducer</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">)</span>\n\n    <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toHaveLength</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toContainEqual</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token string\">'returns new state with action notes/toggleImportanceOf'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span>  <span class=\"token keyword\">const</span> state <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'the app state is in redux store'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'state changes are made with actions'</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span>\n\n  <span class=\"token keyword\">const</span> action <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">type</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes/toggleImportanceOf'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">payload</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span></span>  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">deepFreeze</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> newState <span class=\"token operator\">=</span> <span class=\"token function\">noteReducer</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">,</span> action<span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toHaveLength</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toContainEqual</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">expect</span><span class=\"token punctuation\">(</span>newState<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toContainEqual</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'state changes are made with actions'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Sovelluksen tämänhetkinen koodi on <a href=\"https://github.com/fullstack-hy2020/redux-notes/tree/part6-3\">GitHubissa</a> branchissa </i>part6-3</i>.</p>\n<h3>Redux Toolkit ja console.log</h3>\n<p>Kuten olemme oppineet, on <em>console.log</em> äärimmäisen voimakas työkalu, se pelastaa meidät yleensä aina pulasta.</p>\n<p>Yritetään kokeeksi tulostaa <i>Redux</i>-storen tila konsoliin kesken funktiolla <em>createSlice</em> luodun reducerin: </p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> noteSlice <span class=\"token operator\">=</span> <span class=\"token function\">createSlice</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes'</span><span class=\"token punctuation\">,</span>\n  initialState<span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">reducers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// ...</span>\n    <span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> id <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload\n\n      <span class=\"token keyword\">const</span> noteToChange <span class=\"token operator\">=</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">n</span> <span class=\"token operator\">=></span> n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> id<span class=\"token punctuation\">)</span>\n\n      <span class=\"token keyword\">const</span> changedNote <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> \n        <span class=\"token operator\">...</span>noteToChange<span class=\"token punctuation\">,</span> \n        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>noteToChange<span class=\"token punctuation\">.</span>important \n      <span class=\"token punctuation\">}</span>\n\n<span class=\"gatsby-highlight-code-line\">      console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span></span>\n      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span>\n        note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id <span class=\"token operator\">?</span> note <span class=\"token operator\">:</span> changedNote \n      <span class=\"token punctuation\">)</span>     \n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Kun nyt muistiinpanon tärkeyttä muuttaa klikkaamalla sen nimeä, konsoliin tulostuu seuraava</p>\n<picture><img src=\"/static/8ef34beed113ccac9b86bb5a85106839/5a190/40new.png\" srcset=\"/static/8ef34beed113ccac9b86bb5a85106839/772e8/40new.png 200w,\n/static/8ef34beed113ccac9b86bb5a85106839/e17e5/40new.png 400w,\n/static/8ef34beed113ccac9b86bb5a85106839/5a190/40new.png 800w,\n/static/8ef34beed113ccac9b86bb5a85106839/c1b63/40new.png 1200w,\n/static/8ef34beed113ccac9b86bb5a85106839/d7ceb/40new.png 1446w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Tulostus on mielenkiintoinen mutta ei kovin hyödyllinen. Kyse tässä jo edellä mainitusta Redux toolkitin käyttämästä Immer-kirjastosta, mitä käytetään nyt sisäisesti storen tilan tallentamiseen. </p>\n<p>Tilan voi muuntaa ihmisluettavaan muotoon käyttämällä immer-kirjaston <a href=\"https://redux-toolkit.js.org/api/other-exports#current\">current</a>-funktiota. Funktion voi importata käyttöön komennolla:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> current <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@reduxjs/toolkit'</span></code></pre></div>\n<p>ja tämän jälkeen tilan voi tulostaa konsoliin komennolla:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token function\">current</span><span class=\"token punctuation\">(</span>state<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Konsolitulostus on nyt ihmisluettava:</p>\n<picture><img src=\"/static/a0ac14e298c121b64193a9c9fc7612a7/5a190/41new.png\" srcset=\"/static/a0ac14e298c121b64193a9c9fc7612a7/772e8/41new.png 200w,\n/static/a0ac14e298c121b64193a9c9fc7612a7/e17e5/41new.png 400w,\n/static/a0ac14e298c121b64193a9c9fc7612a7/5a190/41new.png 800w,\n/static/a0ac14e298c121b64193a9c9fc7612a7/c1b63/41new.png 1200w,\n/static/a0ac14e298c121b64193a9c9fc7612a7/1dbe8/41new.png 1374w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<h3>Redux DevTools</h3>\n<p>Chromeen on asennettavissa <a href=\"https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=fi\">Redux DevTools</a> ‑lisäosa, jonka avulla Redux-storen tilaa ja sitä muuttavia actioneja on mahdollisuus seurata selaimen konsolista. Redux Toolkitin <em>configureStore</em>-funktion avulla luodussa storessa Redux DevTools on käytössä automaattisesti ilman ylimääräistä konfigurointia.</p>\n<p>Kun lisäosa on asennettu Chromeen, konsolin <i>Redux</i>-välilehti pitäisi näyttää seuraavalta:</p>\n<picture><img src=\"/static/701f103758adbe487ccab1b35193b73b/5a190/42new.png\" alt=\"Redux DevToolsin oikea puoli &#x22;State&#x22; näyttää storen alkutilan\" srcset=\"/static/701f103758adbe487ccab1b35193b73b/772e8/42new.png 200w,\n/static/701f103758adbe487ccab1b35193b73b/e17e5/42new.png 400w,\n/static/701f103758adbe487ccab1b35193b73b/5a190/42new.png 800w,\n/static/701f103758adbe487ccab1b35193b73b/c1b63/42new.png 1200w,\n/static/701f103758adbe487ccab1b35193b73b/29007/42new.png 1600w,\n/static/701f103758adbe487ccab1b35193b73b/eff3b/42new.png 2072w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Kunkin actionin storen tilaan aiheuttamaa muutosta on helppo tarkastella:</p>\n<picture><img src=\"/static/a07b4449f8ccc50f0799cab37c58e527/5a190/43new.png\" alt=\"edux DevToolsin vasen puoli näyttää suoritetut actionit, muuttunut tila heijastuu oikealle puolelle\" srcset=\"/static/a07b4449f8ccc50f0799cab37c58e527/772e8/43new.png 200w,\n/static/a07b4449f8ccc50f0799cab37c58e527/e17e5/43new.png 400w,\n/static/a07b4449f8ccc50f0799cab37c58e527/5a190/43new.png 800w,\n/static/a07b4449f8ccc50f0799cab37c58e527/c1b63/43new.png 1200w,\n/static/a07b4449f8ccc50f0799cab37c58e527/29007/43new.png 1600w,\n/static/a07b4449f8ccc50f0799cab37c58e527/0486e/43new.png 2008w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Konsolin avulla on myös mahdollista dispatchata actioneja storeen:</p>\n<picture><img src=\"/static/13bec7266d827fff56a284a03e9de538/5a190/44new.png\" alt=\"Mahdollisuus actionien dispatchaamiseen avautuu alalaidan valinnoista\" srcset=\"/static/13bec7266d827fff56a284a03e9de538/772e8/44new.png 200w,\n/static/13bec7266d827fff56a284a03e9de538/e17e5/44new.png 400w,\n/static/13bec7266d827fff56a284a03e9de538/5a190/44new.png 800w,\n/static/13bec7266d827fff56a284a03e9de538/c1b63/44new.png 1200w,\n/static/13bec7266d827fff56a284a03e9de538/29007/44new.png 1600w,\n/static/13bec7266d827fff56a284a03e9de538/cb93d/44new.png 2304w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n</div>\n<div class=\"tasks\">\n<h3>Tehtävät 6.10-6.13</h3>\n<h4>6.10 anekdootit, step8</h4>\n<p>Asenna projektiin Redux Toolkit. Siirrä tämän jälkeen Redux-storen määrittely omaan tiedostoon <i>store.js</i> ja hyödynnä sen luonnissa Redux Toolkitin <em>configureStore</em>-funktiota. </p>\n<p>Muuta <i>filter reduserin ja action creatorien</i> määrittely tapahtumaan Redux Toolkitin <em>createSlice</em>-funktion avulla.</p>\n<p>Ota myös käyttöön Redux DevTools sovelluksen tilan debuggaamisen helpottamiseksi.</p>\n<h4>6.11 anekdootit, step9</h4>\n<p>Muuta myös <i>anekdoottireduserin ja action creatorien</i> määrittely tapahtumaan Redux Toolkitin <em>createSlice</em>-funktion avulla.</p>\n<h4>6.12 anekdootit, step10</h4>\n<p>Sovelluksessa on valmiina komponentin <i>Notification</i> runko:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Notification</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> style <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">border</span><span class=\"token operator\">:</span> <span class=\"token string\">'solid'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">padding</span><span class=\"token operator\">:</span> <span class=\"token number\">10</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">borderWidth</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">marginBottom</span><span class=\"token operator\">:</span> <span class=\"token number\">10</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div style<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>style<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      render here notification<span class=\"token operator\">...</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> Notification</code></pre></div>\n<p>Laajenna komponenttia siten, että se renderöi Redux-storeen talletetun viestin. Tee toiminnallisuutta varten oma reduceri ja hyödynnä jälleen Redux Toolkitin <em>createSlice</em>-funktiota.</p>\n<p>Tässä vaiheessa sovelluksen ei vielä tarvitse osata käyttää <i>Notification</i>-komponenttia järkevällä tavalla, vaan riittää että sovellus toimii ja näyttää <i>notificationReducerin</i> alkuarvoksi asettaman viestin.</p>\n<h4>6.13 anekdootit, step11</h4>\n<p>Laajenna sovellusta siten, että se näyttää <i>Notification</i>-komponentin avulla viiden sekunnin ajan, kun sovelluksessa äänestetään tai luodaan uusia anekdootteja:</p>\n<picture><img src=\"/static/c4f460152b68a605ba70ae47ef09301e/5a190/8eb.png\" alt=\"Äänestyksen yhteydessä näytetään notifikaatio: you voted &#x27;if it hurts, do it more often&#x27;\" srcset=\"/static/c4f460152b68a605ba70ae47ef09301e/772e8/8eb.png 200w,\n/static/c4f460152b68a605ba70ae47ef09301e/e17e5/8eb.png 400w,\n/static/c4f460152b68a605ba70ae47ef09301e/5a190/8eb.png 800w,\n/static/c4f460152b68a605ba70ae47ef09301e/35a31/8eb.png 1028w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Notifikaation asettamista ja poistamista varten kannattaa toteuttaa <a href=\"https://redux-toolkit.js.org/api/createSlice#reducers\">action creatorit</a>.</p>\n</div>\n<div class=\"content\">\n<h3>JSON Serverin käyttöönotto</h3>\n<p>Laajennetaan sovellusta siten, että muistiinpanot talletetaan backendiin. Käytetään osasta 2 tuttua <a href=\"/osa2/palvelimella_olevan_datan_hakeminen\">JSON Serveriä</a>.</p>\n<p>Tallennetaan projektin juureen tiedostoon <i>db.json</i> tietokannan alkutila:</p>\n<div class=\"gatsby-highlight\" data-language=\"json\"><pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"notes\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"content\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"the app state is in redux store\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"important\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"content\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"state changes are made with actions\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"important\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Asennetaan projektiin JSON Server</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> json-server --save-dev</code></pre></div>\n<p>ja lisätään tiedoston <i>package.json</i> osaan <i>scripts</i> rivi</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token string-property property\">\"scripts\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token string-property property\">\"server\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"json-server -p 3001 db.json\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Käynnistetään JSON Server komennolla <em>npm run server</em>.</p>\n<h3>Fetch API</h3>\n<p>Ohjelmistokehityksessä joudutaan usein pohtimaan, kannattaako jokin toiminnallisuus toteuttaa käyttämällä ulkoista kirjastoa vai onko parempi hyödyntää ympäristön tarjoamia natiiveja ratkaisuja. Molemmilla lähestymistavoilla on omat etunsa ja haasteensa. </p>\n<p>Käytimme HTTP-pyyntöjen tekemiseen kurssin aiemmissa osissa <a href=\"https://axios-http.com/docs/intro\">Axios</a>-kirjastoa. Tutustutaan nyt vaihtoehtoiseen tapaan tehdä HTTP-pyyntöjä natiivia <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\">Fetch APIa</a> hyödyntäen.</p>\n<p>On tyypillistä, että ulkoinen kirjasto kuten <i>Axios</i> on toteutettu hyödyntäen muita ulkoisia kirjastoja. Esimerkiksi jos Axioksen asentaa projektiin komennolla <em>npm install axios</em>, konsoliin tulostuu: </p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">$ <span class=\"token function\">npm</span> <span class=\"token function\">install</span> axios\n\nadded <span class=\"token number\">23</span> packages, and audited <span class=\"token number\">302</span> packages <span class=\"token keyword\">in</span> 1s\n\n<span class=\"token number\">71</span> packages are looking <span class=\"token keyword\">for</span> funding\n  run <span class=\"token variable\"><span class=\"token variable\">`</span><span class=\"token function\">npm</span> fund<span class=\"token variable\">`</span></span> <span class=\"token keyword\">for</span> details\n\nfound <span class=\"token number\">0</span> vulnerabilities</code></pre></div>\n<p>Komento asentaisi projektiin siis Axios-kirjaston lisäksi yli 20 muuta npm-pakettia, jotka Axios tarvitsisi toimiakseen. </p>\n<p><i>Fetch API</i> tarjoaa samankaltaisen tavan tehdä HTTP-pyyntöjä kuin Axios, mutta Fetch APIn käyttäminen ei vaadi ulkoisten kirjastojen asentamista. Sovelluksen ylläpito helpottuu, kun päivitettäviä kirjastoja on vähemmän, ja myös tietoturva paranee, koska sovelluksen mahdollinen hyökkäyspinta-ala pienenee. Sovellusten tietoturvaa ja ylläpitoa sivutaan kurssin <a href=\"https://fullstackopen.com/osa7/luokkakomponentit_sekalaista#react-node-sovellusten-tietoturva\">osassa 7</a>.</p>\n<p>Pyyntöjen tekeminen tapahtuu käytännössä käyttämällä <em>fetch()</em>-funktiota. Käytettävässä syntaksissa on jonkin verran eroja verrattuna Axiokseen. Huomaamme myös pian, että Axios on huolehtinut joistakin asioista puolestamme ja helpottanut elämäämme. Käytämme nyt kuitenkin Fetch APIa, koska se on laajasti käytetty natiiviratkaisu, joka jokaisen Full Stack -kehittäjän on syytä tuntea.</p>\n<h3>Datan hakeminen palvelimelta</h3>\n<p>Tehdään backendistä dataa hakeva metodi tiedostoon <i>src/services/notes.js</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> baseUrl <span class=\"token operator\">=</span> <span class=\"token string\">'http://localhost:3001/notes'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">getAll</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>baseUrl<span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>response<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to fetch notes'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> data <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">return</span> data\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token punctuation\">{</span> getAll <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Tutkitaan <em>getAll</em>-metodin toteutusta tarkemmin. Muistiinpanot haetaan backendistä nyt kutsumalla <em>fetch()</em>-funktiota, jolle on annettu argumentiksi backendin URL-osoite. Pyynnön tyyppiä ei ole erikseen määritelty, joten <em>fetch</em> toteuttaa oletusarvoisen toiminnon eli GET-pyynnön.</p>\n<p>Kun vastaus on saapunut, tarkistetaan pyynnön onnistuminen vastauksen kentästä <em>response.ok</em> ja heitetään tarvittaessa virhe:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>response<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to fetch notes'</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Attribuutti <em>response.ok</em> saa arvon <em>true</em>, jos pyyntö on onnistunut eli jos vastauksen statuskoodi on välillä 200-299. Kaikilla muilla statuskoodeilla, esimerkiksi 404 tai 500, se saa arvon <em>false</em>. </p>\n<p>Huomaa, että <em>fetch</em> ei automaattisesti heitä virhettä, vaikka vastauksen statuskoodi olisi esimerkiksi 404. Virheenkäsittely tulee toteuttaa manuaalisesti, kuten olemme nyt tehneet.</p>\n<p>Jos pyyntö on onnistunut, vastauksen sisältämä data muunnetaan JSON-muotoon:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> data <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><em>fetch</em> ei siis automaattisesti muunna vastauksen mukana mahdollisesti olevaa dataa JSON-muotoon, vaan muunnos tulee tehdä manuaalisesti. On myös hyvä huomata, että <em>response.json()</em> on asynkroninen metodi, eli sen kanssa tulee käyttää <i>await</i>-avainsanaa.</p>\n<p>Suoraviivaistetaan koodia vielä hieman palauttamalla suoraan metodin <em>response.json()</em> palauttama data:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">getAll</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>baseUrl<span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>response<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to fetch notes'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span><span class=\"token punctuation\">}</span></code></pre></div>\n<h3>Storen alustaminen palvelimelta haetulla datalla</h3>\n<p>Muutetaan nyt sovellustamme siten, että sovelluksen tila alustetaan palvelimelta haetuilla muistiinpanoilla. </p>\n<p>Muutetaan tiedostossa <i>noteReducer.js</i> tapahtuvaa muistiinpanojen tilan alustusta siten, että oletusarvoisesti muistiinpanoja ei ole:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> noteSlice <span class=\"token operator\">=</span> <span class=\"token function\">createSlice</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes'</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token literal-property property\">initialState</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span></span>  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Lisätään action creator <em>setNotes</em>, jonka avulla muistiinpanojen taulukon voi suoraan korvata. Saamme <em>createSlice</em>-funktion avulla luotua haluamamme action creatorin seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// ...</span>\n\n<span class=\"token keyword\">const</span> noteSlice <span class=\"token operator\">=</span> <span class=\"token function\">createSlice</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">initialState</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">reducers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload\n      state<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n        content<span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token function\">generateId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> id <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload\n      <span class=\"token keyword\">const</span> noteToChange <span class=\"token operator\">=</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">n</span> <span class=\"token operator\">=></span> n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> id<span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> changedNote <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">...</span>noteToChange<span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>noteToChange<span class=\"token punctuation\">.</span>important\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id <span class=\"token operator\">?</span> note <span class=\"token operator\">:</span> changedNote<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">setNotes</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token keyword\">return</span> action<span class=\"token punctuation\">.</span>payload</span><span class=\"gatsby-highlight-code-line\">    <span class=\"token punctuation\">}</span></span>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createNote<span class=\"token punctuation\">,</span> toggleImportanceOf<span class=\"token punctuation\">,</span> setNotes <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> noteSlice<span class=\"token punctuation\">.</span>actions</span><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> noteSlice<span class=\"token punctuation\">.</span>reducer</code></pre></div>\n<p>Toteutetaan muistiinpanojen alustus <i>App</i>-komponentiin, eli kuten yleensä dataa palvelimelta haettaessa, käytetään <i>useEffect</i>-hookia:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useDispatch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span></span>\n<span class=\"token keyword\">import</span> NoteForm <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/NoteForm'</span>\n<span class=\"token keyword\">import</span> Notes <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/Notes'</span>\n<span class=\"token keyword\">import</span> VisibilityFilter <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/VisibilityFilter'</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> setNotes <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> noteService <span class=\"token keyword\">from</span> <span class=\"token string\">'./services/notes'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    noteService<span class=\"token punctuation\">.</span><span class=\"token function\">getAll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">notes</span> <span class=\"token operator\">=></span> <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">setNotes</span><span class=\"token punctuation\">(</span>notes<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>dispatch<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>NoteForm <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>VisibilityFilter <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>Notes <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> App</code></pre></div>\n<p>Muistiinpanot haetaan palvelimelta siis käyttäen määrittelemäämme <em>getAll()</em>-metodia ja tallennetaan sitten Redux-storeen dispatchaamalla <em>setNotes</em> -action creatorin palauttama action. Toiminnot tehdään <i>useEffect</i>-hookissa eli ne suoritetaan App-komponentin ensimmäisen renderoinnin yhteydessä.</p>\n<p>Tutkitaan vielä tarkemmin erästä pientä yksityiskohtaa. Olemme lisänneet <em>dispatch</em>-muuttujan <i>useEffect</i>-hookin riippuvuustaulukkoon. Jos yritämme käyttää tyhjää riippuvuustaulukkoa, ESLint antaa seuraavan varoituksen: <i>React Hook useEffect has a missing dependency: 'dispatch'</i>. Mistä on kyse?</p>\n<p>Koodi toimisi loogisesti täysin samoin, vaikka käyttäisimme tyhjää riippuvuustaulukkoa, koska dispatch viittaa samaan funktioon koko ohjelman suorituksen ajan. On kuitenkin hyvän ohjelmointikäytännön mukaista lisätä <em>useEffect</em>-hookin riippuvuuksiksi kaikki sen käyttämät muuttujat ja funktiot, jotka on määritelty kyseisen komponentin sisällä. Näin voidaan välttää yllättäviä bugeja.</p>\n<h3>Datan lähettäminen palvelimelle</h3>\n<p>Toteutetaan seuraavaksi toiminnallisuus uuden muistiinpanon lähettämiseksi palvelimelle. Pääsemme samalla harjoittelemaan, miten POST-pyyntö tehdään <em>fetch()</em>-metodia käyttäen.</p>\n<p>Laajennetaan tiedostossa <i>src/services/notes.js</i> olevaa palvelimen kanssa kommunikoivaa koodia seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> baseUrl <span class=\"token operator\">=</span> <span class=\"token string\">'http://localhost:3001/notes'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">getAll</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>baseUrl<span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>response<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to fetch notes'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">createNew</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">content</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>baseUrl<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">method</span><span class=\"token operator\">:</span> <span class=\"token string\">'POST'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">headers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token string-property property\">'Content-Type'</span><span class=\"token operator\">:</span> <span class=\"token string\">'application/json'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">body</span><span class=\"token operator\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> content<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>response<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to create note'</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">  </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token punctuation\">{</span> getAll<span class=\"token punctuation\">,</span> createNew <span class=\"token punctuation\">}</span></span></code></pre></div>\n<p>Tutkitaan <em>createNew</em>-metodin toteutusta tarkemmin. <em>fetch()</em>-funktion ensimmäinen parametri määrittelee URL-osoitteen, johon pyyntö tehdään. Toinen parametri on olio, joka määrittelee muut pyynnön yksityiskohdat, kuten pyynnön tyypin, otsikot ja pyynnön mukana lähetettävän datan. Voimme selkeyttää koodia vielä hieman tallentamalla pyynnön yksityiskohdat määrittelevän olion erilliseen <i>options</i>-apumuuttujaan:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">createNew</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">content</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> options <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">method</span><span class=\"token operator\">:</span> <span class=\"token string\">'POST'</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">headers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token string-property property\">'Content-Type'</span><span class=\"token operator\">:</span> <span class=\"token string\">'application/json'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token literal-property property\">body</span><span class=\"token operator\">:</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> content<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">  </span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>baseUrl<span class=\"token punctuation\">,</span> options<span class=\"token punctuation\">)</span></span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>response<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to create note'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Tutkitaan <i>options</i>-oliota tarkemmin:</p>\n<ul>\n<li><i>method</i> määrittelee pyynnön tyypin, joka tässä tapauksessa on <i>POST</i></li>\n<li><i>headers</i> määrittelee pyynnön otsikot. Liitämme pyyntöön otsikon <em>'Content-Type': 'application/json'</em>, jotta palvelin tietää, että pyynnön mukana oleva data on JSON-muotoista, ja osaa käsitellä pyynnön oikein</li>\n<li><i>body</i> sisältää pyynnön mukana lähetettävän datan. Kentään ei voi suoraan sijoittaa JavaScript-oliota, vaan se tulee ensin muuntaa JSON-merkkijonoksi kutsumalla funktiota <em>JSON.stringify()</em></li>\n</ul>\n<p>Kuten GET-pyynnön kanssa, myös nyt vastauksen statuskoodi tutkitaan virheiden varalta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>response<span class=\"token punctuation\">.</span>ok<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Failed to create note'</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Jos pyyntö onnistuu, <i>JSON Server</i> palauttaa juuri luodun muistiinpanon, jolle se on generoinut myös yksilöllisen <i>id</i>:n. Vastauksen sisältämä data tulee kuitenkin vielä muuntaa JSON-muotoon metodilla <em>response.json()</em>: </p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Muutetaan sitten sovelluksemme <i>NoteForm</i>-komponenttia siten, että uusi muistiinpano lähetetään backendiin. Komponentin metodi <em>addNote</em> muuttuu hiukan:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useDispatch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createNote <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'../reducers/noteReducer'</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> noteService <span class=\"token keyword\">from</span> <span class=\"token string\">'../services/notes'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">NoteForm</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">props</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  \n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">addNote</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span>    event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value\n    event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value <span class=\"token operator\">=</span> <span class=\"token string\">''</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> newNote <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> noteService<span class=\"token punctuation\">.</span><span class=\"token function\">createNew</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span>newNote<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>form onSubmit<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>addNote<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input name<span class=\"token operator\">=</span><span class=\"token string\">\"note\"</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button type<span class=\"token operator\">=</span><span class=\"token string\">\"submit\"</span><span class=\"token operator\">></span>add<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> NoteForm</code></pre></div>\n<p>Kun uusi muistiinpano luodaan backendiin kutsumalla <em>createNew()</em>-metodia, saadaan paluuarvona muistiinpanoa kuvaava olio, jolle backend on generoinut <i>id</i>:n. Muutetaan siksi tiedostossa <i>notesReducer.js</i> määritelty action creator <i>createNote</i> seuraavaan muotoon:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> noteSlice <span class=\"token operator\">=</span> <span class=\"token function\">createSlice</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">initialState</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">reducers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">      state<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span></span>    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token comment\">// ..</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Muistiinpanojen tärkeyden muuttaminen olisi mahdollista toteuttaa samalla periaatteella, eli tehdä palvelimelle ensin asynkroninen metodikutsu ja sen jälkeen dispatchata sopiva action.</p>\n<p>Sovelluksen tämänhetkinen koodi on <a href=\"https://github.com/fullstack-hy2020/redux-notes/tree/part6-4\">GitHubissa</a> branchissa <i>part6-4</i>.</p>\n</div>\n<div class=\"tasks\">\n<h3>Tehtävät 6.14.-6.15.</h3>\n<h4>6.14 anekdootit ja backend, step1</h4>\n<p>Hae sovelluksen käynnistyessä anekdootit JSON Serverillä toteutetusta backendistä. Käytä HTTP-pyynnön tekemiseen Fetch APIa.</p>\n<p>Backendin alustavan sisällön saat esim. <a href=\"https://github.com/fullstack-hy2020/misc/blob/master/anecdotes.json\">täältä</a>.</p>\n<h4>6.15 anekdootit ja backend, step2</h4>\n<p>Muuta uusien anekdoottien luomista siten, että anekdootit talletetaan backendiin. Hyödynnä toteutuksessasi jälleen Fetch APIa.</p>\n</div>\n<div class=\"content\">\n<h3>Asynkroniset actionit ja Redux Thunk</h3>\n<p>Lähestymistapamme on melko hyvä, mutta siinä mielessä ikävä, että palvelimen kanssa kommunikointi tapahtuu komponentit määrittelevien funktioiden koodissa. Olisi parempi, jos kommunikointi voitaisiin abstrahoida komponenteilta siten, että niiden ei tarvitsisi kuin kutsua sopivaa <i>action creatoria</i>. Esim. <i>App</i> voisi alustaa sovelluksen tilan seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">initializeNotes</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>dispatch<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> \n  \n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><i>NoteForm</i> puolestaan loisi uuden muistiinpanon seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">NoteForm</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  \n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">addNote</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value\n    event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value <span class=\"token operator\">=</span> <span class=\"token string\">''</span>\n    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Molemmat komponentit dispatchaisivat ainoastaan actionin välittämättä siitä, että taustalla tapahtuu todellisuudessa palvelimen kanssa tapahtuvaa kommunikointia. Tämän kaltaisten <i>asynkronisten actioneiden</i> käyttö onnistuu <a href=\"https://github.com/reduxjs/redux-thunk\">Redux Thunk</a>-kirjaston avulla. Kirjaston käyttö ei vaadi ylimääräistä konfiguraatiota eikä asennusta, kun Redux-store on luotu Redux Toolkitin <em>configureStore</em>-funktiolla.</p>\n<p>Redux Thunkin ansiosta on mahdollista määritellä <i>action creatoreja</i>, jotka palauttavat objektin sijaan funktion. Tämän ansiosta on mahdollista toteuttaa asynkronisia action creatoreja, jotka ensin odottavat jonkin asynkronisen toimenpiteen valmistumista ja vasta sen jälkeen dispatchaavat varsinaisen actionin. </p>\n<p>Jos action creator palauttaa funktion, Redux välittää palautetulle funktiolle automaattisesti Redux-storen <em>dispatch</em>- ja <em>getState</em>-metodit argumenteiksi. Sen ansiosta voimme määritellä muistiinpanojen alkutilan palvelimelta hakevan action creatorin <em>initializeNotes</em> tiedostossa <i>noteReducer.js</i> seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createSlice <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@reduxjs/toolkit'</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> noteService <span class=\"token keyword\">from</span> <span class=\"token string\">'../services/notes'</span></span>\n<span class=\"token keyword\">const</span> noteSlice <span class=\"token operator\">=</span> <span class=\"token function\">createSlice</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">initialState</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">reducers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      state<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> id <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload\n      <span class=\"token keyword\">const</span> noteToChange <span class=\"token operator\">=</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">n</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> id<span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> changedNote <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">...</span>noteToChange<span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>noteToChange<span class=\"token punctuation\">.</span>important<span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id <span class=\"token operator\">?</span> note <span class=\"token operator\">:</span> changedNote<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function\">setNotes</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> action<span class=\"token punctuation\">.</span>payload\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> setNotes <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> noteSlice<span class=\"token punctuation\">.</span>actions</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">initializeNotes</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">return</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">dispatch</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> noteService<span class=\"token punctuation\">.</span><span class=\"token function\">getAll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">setNotes</span><span class=\"token punctuation\">(</span>notes<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createNote<span class=\"token punctuation\">,</span> toggleImportanceOf <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> noteSlice<span class=\"token punctuation\">.</span>actions</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> noteSlice<span class=\"token punctuation\">.</span>reducer</code></pre></div>\n<p>Sisemmässä funktiossaan eli <i>asynkronisessa actionissa</i> operaatio hakee ensin palvelimelta kaikki muistiinpanot ja sen jälkeen <i>dispatchaa</i> muistiinpanot storeen lisäävän actionin. Huomionarvioista on se, että Redux välittää <em>dispatch</em>-metodin viitteen automaattisesti funktion argumentiksi, eli action creator <em>initializeNotes</em> ei tarvitse mitään parametreja.</p>\n<p>Action creatoria <em>setNotes</em> ei enää exportata moduulin ulkopuolelle, koska muistiinpanojen alkutila on tarkoitus asettaa jatkossa käytämällä tekemäämme asynkronista action creatoria <em>initialNotes</em>. Hyödynnämme kuitenkin edelleen <em>setNotes</em> -action creatoria moduulin sisällä.</p>\n<p>Komponentti <i>App</i> voidaan nyt määritellä seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useDispatch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n\n<span class=\"token keyword\">import</span> NoteForm <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/NoteForm'</span>\n<span class=\"token keyword\">import</span> Notes <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/Notes'</span>\n<span class=\"token keyword\">import</span> VisibilityFilter <span class=\"token keyword\">from</span> <span class=\"token string\">'./components/VisibilityFilter'</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> initializeNotes <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./reducers/noteReducer'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">initializeNotes</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>dispatch<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>NoteForm <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>VisibilityFilter <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>Notes <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> App</code></pre></div>\n<p>Ratkaisu on elegantti, sillä muistiinpanojen alustuslogiikka on eriytetty kokonaan React-komponenttien ulkopuolelle.</p>\n<p>Luodaan seuraavaksi <em>appendNote</em>-niminen asynkroninen action creator:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createSlice <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@reduxjs/toolkit'</span>\n<span class=\"token keyword\">import</span> noteService <span class=\"token keyword\">from</span> <span class=\"token string\">'../services/notes'</span>\n\n<span class=\"token keyword\">const</span> noteSlice <span class=\"token operator\">=</span> <span class=\"token function\">createSlice</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> <span class=\"token string\">'notes'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">initialState</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">reducers</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      state<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">.</span>payload<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function\">toggleImportanceOf</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> id <span class=\"token operator\">=</span> action<span class=\"token punctuation\">.</span>payload\n      <span class=\"token keyword\">const</span> noteToChange <span class=\"token operator\">=</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">n</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> id<span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">const</span> changedNote <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token operator\">...</span>noteToChange<span class=\"token punctuation\">,</span>\n        <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>noteToChange<span class=\"token punctuation\">.</span>important<span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token keyword\">return</span> state<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id <span class=\"token operator\">?</span> note <span class=\"token operator\">:</span> changedNote<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function\">setNotes</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state<span class=\"token punctuation\">,</span> action</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> action<span class=\"token punctuation\">.</span>payload\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> createNote<span class=\"token punctuation\">,</span> setNotes <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> noteSlice<span class=\"token punctuation\">.</span>actions</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">initializeNotes</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">dispatch</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> noteService<span class=\"token punctuation\">.</span><span class=\"token function\">getAll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">setNotes</span><span class=\"token punctuation\">(</span>notes<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">appendNote</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">content</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">return</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">dispatch</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token keyword\">const</span> newNote <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> noteService<span class=\"token punctuation\">.</span><span class=\"token function\">createNew</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">createNote</span><span class=\"token punctuation\">(</span>newNote<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span></span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> toggleImportanceOf <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> noteSlice<span class=\"token punctuation\">.</span>actions</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> noteSlice<span class=\"token punctuation\">.</span>reducer</code></pre></div>\n<p>Periaate on jälleen sama. Ensin suoritetaan asynkroninen operaatio, ja sen valmistuttua <i>dispatchataan</i> storen tilaa muuttava action. <em>createNote</em> -action creatoria ei enää exportata tiedoston ulkopuolelle, vaan sitä käytetään ainoastaan sisäisesti <em>appendNote</em> -funktion toteutuksessa. </p>\n<p>Komponentti <i>NoteForm</i> yksinkertaistuu seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useDispatch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react-redux'</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> appendNote <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'../reducers/noteReducer'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">NoteForm</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> dispatch <span class=\"token operator\">=</span> <span class=\"token function\">useDispatch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">addNote</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    event<span class=\"token punctuation\">.</span><span class=\"token function\">preventDefault</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">const</span> content <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value\n    event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value <span class=\"token operator\">=</span> <span class=\"token string\">''</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">appendNote</span><span class=\"token punctuation\">(</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span>  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>form onSubmit<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>addNote<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input name<span class=\"token operator\">=</span><span class=\"token string\">\"note\"</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button type<span class=\"token operator\">=</span><span class=\"token string\">\"submit\"</span><span class=\"token operator\">></span>add<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Sovelluksen tämänhetkinen koodi on <a href=\"https://github.com/fullstack-hy2020/redux-notes/tree/part6-5\">GitHubissa</a> branchissa <i>part6-5</i>.</p>\n<p>Redux Toolkit tarjoaa myös hieman kehittyneempiä työkaluja asynkronisen tilanhallinnan helpottamiseksi, esim mm. <a href=\"https://redux-toolkit.js.org/api/createAsyncThunk\">createAsyncThunk</a>-funktion ja <a href=\"https://redux-toolkit.js.org/rtk-query/overview\">RTK Query</a> ‑API:n. Yksinkertaisissa sovelluksissa näiden tuoma hyöty lienee kuitenkin vähäinen.</p>\n</div>\n<div class=\"tasks\">\n<h3>Tehtävät 6.16.-6.19.</h3>\n<h4>6.16 anekdootit ja backend, step3</h4>\n<p>Muuta Redux-storen alustus tapahtumaan Redux Thunk ‑kirjaston avulla toteutettuun asynkroniseen actioniin.</p>\n<h4>6.17 anekdootit ja backend, step4</h4>\n<p>Muuta myös uuden anekdootin luominen tapahtumaan Redux Thunk ‑kirjaston avulla toteutettuihin asynkronisiin actioneihin.</p>\n<h4>6.18 anekdootit ja backend, step5</h4>\n<p>Äänestäminen ei vielä talleta muutoksia backendiin. Korjaa tilanne Redux Thunk ‑kirjastoa ja Fetch APIa hyödyntäen.</p>\n<h4>6.19 anekdootit ja backend, step6</h4>\n<p>Notifikaatioiden tekeminen on nyt hieman ikävää, sillä se edellyttää kahden actionin tekemistä ja <em>setTimeout</em>-funktion käyttöä:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">setNotification</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">new anecdote '</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>content<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">'</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">clearNotification</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token number\">5000</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Toteuta action creator, joka mahdollistaa notifikaation antamisen seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token function\">dispatch</span><span class=\"token punctuation\">(</span><span class=\"token function\">setNotification</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">you voted '</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>anecdote<span class=\"token punctuation\">.</span>content<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">'</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Ensimmäisenä parametrina on renderöitävä teksti ja toisena notifikaation näyttöaika sekunneissa.</p>\n<p>Ota paranneltu notifikaatiotapa käyttöön sovelluksessasi.</p>\n</div>","frontmatter":{"mainImage":{"publicURL":"/static/a3b7bc3fafcb5b47227616e1343970e5/part-6.svg"},"part":6,"letter":"d","lang":"fi"}}},"pageContext":{"part":6,"letter":"d","lang":"fi"}},"staticQueryHashes":["3128451518"]}