{"componentChunkName":"component---src-templates-content-template-js","path":"/osa6/flux_arkkitehtuuri_ja_zustand","result":{"data":{"markdownRemark":{"html":"<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> komponenteissa. 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 erikseen tähän tarkoitettujen <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>Flux-arkkitehtuuria noudattava <a href=\"https://redux.js.org\">Redux</a> oli lähes vuosikymmenen hallitseva tilanhallintaratkaisu React-sovelluksissa. Myös tällä kurssilla käytettiin Reduxia kevääseen 2026 asti. Reduxia on alusta asti vaivannut monimutkaisuus ja boilerplate-koodin suuri määrä. Tilanne parani huomattavasti <a href=\"https://redux-toolkit.js.org/\">Redux Toolkitin</a> ilmestymisen myötä, mutta tästä huolimatta yhteisö kehitti koko ajan vaihtoehtoisia tilanhallintaratkaisuja, kuten esimerkiksi <a href=\"https://mobx.js.org/\">MobX</a>, <a href=\"https://recoiljs.org/\">Recoil</a>  ja <a href=\"https://www.npmjs.com/package/jotai\">Jotai</a>. Näiden suosio on ollut vaihtelevaa. </p>\n<p>Mielenkiintoisin, ja suosituin uusista tulokkaista on ehdottomasti <a href=\"https://zustand.docs.pmnd.rs/\">Zustand</a>, ja se on myös meidän valintamme tilanhallintaratkaisuksi. Zustand näyttää tavoittaneen suosiossaan jo itsensä Reduxin:</p>\n<picture><img src=\"/static/e42a923e1e5e4de59c967d02d3e14342/5a190/redux-vs-rest.png\" srcset=\"/static/e42a923e1e5e4de59c967d02d3e14342/772e8/redux-vs-rest.png 200w,\n/static/e42a923e1e5e4de59c967d02d3e14342/e17e5/redux-vs-rest.png 400w,\n/static/e42a923e1e5e4de59c967d02d3e14342/5a190/redux-vs-rest.png 800w,\n/static/e42a923e1e5e4de59c967d02d3e14342/c1b63/redux-vs-rest.png 1200w,\n/static/e42a923e1e5e4de59c967d02d3e14342/29007/redux-vs-rest.png 1600w,\n/static/e42a923e1e5e4de59c967d02d3e14342/7ad71/redux-vs-rest.png 2338w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<h3>Zustand</h3>\n<p>Tutustutaan Zustandiin 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>Zustand</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> zustand</code></pre></div>\n<p>Ensimmäinen versio, missä vasta laskurin kasvatus toimii, sovelluksesta on seuraavassa:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">import</span> <span class=\"token punctuation\">{</span> create <span class=\"token punctuation\">}</span> from <span class=\"token string\">'zustand'</span>\n\nconst useCounterStore <span class=\"token operator\">=</span> create<span class=\"token punctuation\">(</span>set <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  counter: <span class=\"token number\">0</span>,\n  increment: <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> set<span class=\"token punctuation\">(</span>state <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> counter: state.counter + <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 punctuation\">))</span>\n\nconst App <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span>\n  const counter <span class=\"token operator\">=</span> useCounterStore<span class=\"token punctuation\">(</span>state <span class=\"token operator\">=</span><span class=\"token operator\">></span> state.counter<span class=\"token punctuation\">)</span>\n  const increment <span class=\"token operator\">=</span> useCounterStore<span class=\"token punctuation\">(</span>state <span class=\"token operator\">=</span><span class=\"token operator\">></span> state.increment<span class=\"token punctuation\">)</span>\n\n  <span class=\"token builtin class-name\">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>counter<span class=\"token punctuation\">}</span><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>\n        <span class=\"token operator\">&lt;</span>button <span class=\"token assign-left variable\">onClick</span><span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>increment<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>plus<span class=\"token operator\">&lt;</span>/button<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>button<span class=\"token operator\">></span>minus<span class=\"token operator\">&lt;</span>/button<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>button<span class=\"token operator\">></span>zero<span class=\"token operator\">&lt;</span>/button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>/div<span class=\"token operator\">></span>\n      \n    <span class=\"token operator\">&lt;</span>/div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Sovellus aloittaa luomalla <i>storen</i> eli globaalin tilan Zustandin funktiolla <a href=\"https://zustand.docs.pmnd.rs/reference/apis/create\">create</a>: </p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">import</span> <span class=\"token punctuation\">{</span> create <span class=\"token punctuation\">}</span> from <span class=\"token string\">'zustand'</span>\n\nconst useCounterStore <span class=\"token operator\">=</span> create<span class=\"token punctuation\">(</span>set <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  counter: <span class=\"token number\">0</span>,\n  increment: <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span><span class=\"token operator\">></span> set<span class=\"token punctuation\">(</span>state <span class=\"token operator\">=</span><span class=\"token operator\">></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> counter: state.counter + <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 punctuation\">))</span></code></pre></div>\n<p>Funktio saa parametriksi <i>funktion</i>, joka palauttaa sovellukselle määriteltävän tilan. Parametri on siis seuraava:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token parameter\"><span class=\"token keyword\">set</span></span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">increment</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</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></code></pre></div>\n<p>Tilaan on siis määritelty <i>counter</i>, joka on arvoltaan nolla, sekä <i>increment</i> joka taas on funktio. </p>\n<p>Sovelluksen komponentit pääsevät käsiksi tilassa määriteltyihin arvoihin sekä funktioihin Zustandin <i>createn</i> avulla määritellyn funktion <i>useCounterStore</i> avulla. Komponentti <i>App</i> ottaa <i>selektorien</i> avulla tilasta käyttöönsä siellä olevan arvon <i>counter</i> sekä funktion <i>increment</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\">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 comment\">// using selector to pick right part of the store state</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> counter <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>counter<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> increment <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>increment<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>div<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>counter<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span></span>      <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>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>increment<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>plus<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span></span>        <span class=\"token operator\">&lt;</span>button<span class=\"token operator\">></span>minus<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<span class=\"token operator\">></span>zero<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      \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>Storessa oleva laskurin arvo saadaan siis talletettua muuttujaan seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> counter <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>counter<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Käytössä on selektorifunktio, <i>state => state.counter</i> joka määrää mitä storen sisätä palautetaan. Vastaavalla tavalla saadaan muuttujaan <i>increment</i> storessa oleva funktio.</p>\n<p>Napin \"plus\" klikkauksenkäsittelijäksi on annettu tilan funktio <i>increment</i>, joka  määriteltiin seuraavasti:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> useCounterStore <span class=\"token operator\">=</span> <span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token keyword\">set</span></span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token function-variable function\">increment</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</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></code></pre></div>\n<p>Otetaan funktiomäärittely vielä erilleen:</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 punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Kyseessä on siis funktio, joka kutsuu funktiota <a href=\"https://zustand.docs.pmnd.rs/learn/guides/updating-state\">set</a> antaen parametriksi taas funktion. Tämä parametrina oleva funktio määrittelee miten tila muuttuu:</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> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>joka taas on lyhennysmerkintä seuraavalle:</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> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Funktio palauttaa uuden tilan, jonka se laskee vanhan tilan <i>state</i> perusteella, eli jos vanha tila on esimerkiksi</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\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">increment</span><span class=\"token operator\">:</span> <span class=\"token comment\">// function definition</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>tulee uudeksi tilaksi</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\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">increment</span><span class=\"token operator\">:</span> <span class=\"token comment\">// function definition</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Tilassa on siis koko ajan mukana myös tilaa muuttava funktio <i>increment</i>. </p>\n<p>Tilanmuutosfunktio</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> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p> koskee ainoastaan tilassa olevaan arvoon <i>counter</i>.</p>\n<p>Mikään ei estäisi muuttamasta tilanmuutosfunktiossa myös tilassa olevaa funktiota, eli jos määrittelisimme seuraavasti</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> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">increment</span><span class=\"token operator\">:</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'increment broken'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>kasvatusnappi toimisi vain ensimmäisellä kerralla, tämän jälkeen napin painaminen ainoastaan tulostaisi konsoliin.</p>\n<p>Kun uudeksi tilaksi asetetaan </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> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>päivitetään ainoastaan tilan avaimen <i>counter</i> arvo, eli uusi tila saadaan yhdistämällä vanha tila tilaa muuttavan funktion arvoon. Tämän takia seuraava tilanmuutosfunktio</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> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>ei vaikuta tilaan ollenkaan.</p>\n<p>Täydennetään vielä sovellus muidenkin nappien osalta:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> useCounterStore <span class=\"token operator\">=</span> <span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token keyword\">set</span></span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">increment</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">decrement</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">-</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">zero</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\">set</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 class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">}</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>\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> counter <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>counter<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> increment <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>increment<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> decrement <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>decrement<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> zero <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>zero<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>div<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>counter<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>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>increment<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>plus<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>decrement<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>minus<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>zero<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>zero<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      \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<blockquote>\n<h4>Mikä ihmeen set ja state</h4>\n<p>Mistä <i>set</i> tulee? Se on Zustandin <i>create</i>-funktion tarjoama apufunktio, jonka avulla tila päivitetään. <i>create</i> kutsuu sille annettua parametrifunktiota ja välittää sille <i>set</i>-funktion automaattisesti. Sitä ei siis tarvitse itse kutsua tai tuoda mistään, vaan Zustand hoitaa sen.</p>\n<p>Mistä taas <i>state</i> tulee? Kun <i>set</i>-funktiolle annetaan parametriksi funktio (eikä suoraan uutta tilaobjektia), Zustand kutsuu tätä funktiota antaen sille argumentiksi storen nykyisen tilan. Näin tilanpäivitysfunktioissa pääsee käyttämään vanhaa tilaa uuden laskemiseen.</p>\n</blockquote>\n<h3>Tilan käyttö eri komponenteista</h3>\n<p>Muokataan sovelluksen rakennetta siten, että storen määrittely siirtyy omaan tiedostoon <i>store.js</i> ja näkymä jakautuu useampaan komponenttiin, jotka on määritelty omina tiedostoina.</p>\n<p>Tiedoston <i>store.js</i> sisältö on yllätyksetön</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> useCounterStore <span class=\"token operator\">=</span> <span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token keyword\">set</span></span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">increment</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">decrement</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">-</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">zero</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\">set</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 class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">}</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></code></pre></div>\n<p>Komponentti <i>App</i> pelkistyy seuraavasti</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> Display <span class=\"token keyword\">from</span> <span class=\"token string\">'./Display'</span>\n<span class=\"token keyword\">import</span> Controls <span class=\"token keyword\">from</span> <span class=\"token string\">'./Controls'</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>Display <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>Controls <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>Huomioinarvoista, tässä on se, että komponentti <i>App</i> ei nyt välitä tilaa lapsikomponenteilleen, Itse asiassa komponentti ei edes millään tavalla koske tilaan, storen määrittely on eriytetty täysin komponentin ulkopuolelle.</p>\n<p>Laskurin arvon näyttävä komponentti on yksinkertainen</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> useCounterStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Display</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> counter <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>counter<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><span class=\"token punctuation\">{</span>counter<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 punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> Display</code></pre></div>\n<p>Komponentti siis pääsee laskurin arvoon käsiksi storen määrittelevän funktion <i>useCounterStore</i> kautta. Tämä on monella tapaa kätevää, ei ole esimerkiksi mitään tarvetta siirrellä tilaa komponentille sen propsien kautta.</p>\n<p>Napit määrittelevä komponentti 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> <span class=\"token punctuation\">{</span> useCounterStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Controls</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> increment <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>increment<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> decrement <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>decrement<span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> zero <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>zero<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>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>increment<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>plus<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>decrement<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>minus<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>zero<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>zero<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\">export</span> <span class=\"token keyword\">default</span> Controls</code></pre></div>\n<p>Funktio <i>useCounterStore</i> ottaa parametrinaan selektorifunktion, joka määrittää mitä osaa tilasta halutaan käyttää. Esimerkiksi:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\">  <span class=\"token keyword\">const</span> increment <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>increment<span class=\"token punctuation\">)</span></code></pre></div>\n<p>Tässä selektorifunktio <i>state => state.increment</i> poimii tilasta <i>increment</i>-avaimen arvon, eli funktion, joka kasvattaa laskuria, ja tallentaa sen <i>increment</i>-muuttujaan.</p>\n<p>Voisimme myös ottaa käyttöömme koko 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> state <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token comment\">// tekee saman asian kuin useCounterStore(state => state) eli valitsee koko tilan</span></code></pre></div>\n<p>Nyt  laskurin arvoon ja funktioinin voisi viitata pistenotaatiolla, eli <i>state.counter</i> ja <i>state.counter</i>.</p>\n<p>Herääkin kysymys olisiko mahdollista ottaa useita tilan osia käyttöön destrukturoimalla:</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> useCounterStore <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Controls</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 punctuation\">{</span> increment<span class=\"token punctuation\">,</span> decrement<span class=\"token punctuation\">,</span> zero <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><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>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>increment<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>plus<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>decrement<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>minus<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>zero<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>zero<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\">export</span> <span class=\"token keyword\">default</span> Controls</code></pre></div>\n<p>Ratkaisu toimii, mutta siinä on eräs merkittävä heikkous. Destrukturointi aiheuttaa sen, että <i>Controls</i>-komponentti renderöidään uudelleen aina kun laskurin arvo muuttuu  vaikka komponentti näyttää ainoastaan painikkeet eikä itse arvoa.</p>\n<p>Zustandin paras käytäntö onkin valita tilasta täsmälleen vain ne osat, joita kyseisessä komponentissa tarvitaan. Komponentti renderöityy uudelleen ainoastaan silloin, kun sen valitseman tilan osa muuttuu. Kun sen sijaan kirjoitetaan:</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 punctuation\">{</span> increment<span class=\"token punctuation\">,</span> decrement<span class=\"token punctuation\">,</span> zero <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> </code></pre></div>\n<p>komponentti ei enää reagoi laskurin arvon muutoksiin, koska se ei ole valinnut sitä tilastaan.</p>\n<h3>Tilan uudelleenorganisointi</h3>\n<p>Saamme kuitenkin aikaan varsin nätin ratkaisun uudelleenorganisoimalla tilaa seuraavasti:</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> useCounterStore <span class=\"token operator\">=</span> <span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token keyword\">set</span></span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">actions</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function-variable function\">increment</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">decrement</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">-</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">zero</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\">set</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 class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span>  \n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Tilaa muuttavat funktiot on nyt koottu oman avaimen <i>actions</i> alle, ja ne voidaan valita kokonaisuudessaan ja destrukturoiden: </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\">Controls</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  \n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> increment<span class=\"token punctuation\">,</span> decrement<span class=\"token punctuation\">,</span> zero <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>actions<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>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>increment<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>plus<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>decrement<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>minus<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>zero<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>zero<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></code></pre></div>\n<p>Nyt uudelleenrenderöitymistä ei tapahdu, sillä tilasta on valittu ainoastaan funktiot, jotka pysyvät koko tilan elinajan samana.</p>\n<p>Joidenkin <a href=\"https://tkdodo.eu/blog/working-with-zustand#only-export-custom-hooks\">parhaiden käytänteiden</a> mukaan, koko tilan määrittelevää funktiota ei kannata exportata koko ohjelman käyttöön. Sensijaan kannattaa luoda siitä pienempiä näkymiä, jotka paljastavat vain tarvittavat osat tilasta. Muokataan tilaa <i>state.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> create <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'zustand'</span>\n\n<span class=\"token keyword\">const</span> useCounterStore <span class=\"token operator\">=</span> <span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token keyword\">set</span></span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">actions</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function-variable function\">increment</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">decrement</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\">set</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>counter <span class=\"token operator\">-</span> <span class=\"token number\">1</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">zero</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\">set</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 class=\"token punctuation\">{</span> <span class=\"token literal-property property\">counter</span><span class=\"token operator\">:</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span>  \n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\">// the hook functions that are used elsewhere in app</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\">useCounter</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\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>counter<span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">useCounterControls</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\">useCounterStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>actions<span class=\"token punctuation\">)</span></span></code></pre></div>\n<p>Nyt siis storen määrittelevän moduulin ulkopuolella on käytössä funktiot <i>useCounter</i>, jota kutsumalla saadaan laskurin arvo, sekä  <i>useCounterControls</i> jota kutsumalla saadaan laskurin arvoa muuttavat funktiot. Käyttö muuttuu hieman:</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> useCounter <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Display</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> counter <span class=\"token operator\">=</span> <span class=\"token function\">useCounter</span><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><span class=\"token punctuation\">{</span>counter<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 punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\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> useCounterControls <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">Controls</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 punctuation\">{</span> increment<span class=\"token punctuation\">,</span> decrement<span class=\"token punctuation\">,</span> zero <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useCounterControls</span><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>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>increment<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>plus<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>decrement<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>minus<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>zero<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>zero<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></code></pre></div>\n<p>Näin käytettäessä tilaa, ei ole enää tarvetta käyttää selektorifunktiota, sillä niiden käyttö on piilotettu uusien apufunktioiden määrittelyn sisälle.</p>\n<p>Tarkkasilmäisimmät kiinnittivät huomiota siihen että Zustandiin liittyvät funktiot on nimetty alkamaan sanalla <i>use</i>. Syynä tähän on se, että Zustandin funktion <i>create</i> palauttama funktio, eli esimerkissämme <i>useCounterStore</i> on Reactin <a href=\"https://react.dev/learn/reusing-logic-with-custom-hooks\">custom hook</a>-funktio. Myös omat apufunktiomme <i>useCounter</i> ja <i>useCounterControls</i> ovat käytännössä custom hookeja, koska ne piilottavat sisälleen custom hookin <i>useCounterStore</i> käytön. </p>\n<p>Custom hookeihin taas liittyy joukko sääntöjä, esimerkiksi niiden nimeämisen oletetaan aina alkavan sanalla <i>use</i>. <a href=\"/osa1/monimutkaisempi_tila_reactin_debuggaus#hookien-saannot\">Osassa 1</a> läpikäydyt <a href=\"https://react.dev/warnings/invalid-hook-call-warning\">hookien säännöt</a> koskevat myös custom hookeja!</p>\n</div>\n<div class=\"tasks\">\n<h3>Tehtävä 6.1.</h3>\n<p>Tehdään uusi versio osan 1 Unicafe-tehtävästä. Hoidetaan sovelluksen tilan käsittely Zustandin avulla.</p>\n<p>Voit ottaa sovelluksesi pohjaksi repositoriossa <a href=\"https://github.com/fullstack-hy2020/unicafe-zustand\">https://github.com/fullstack-hy2020/unicafe-zustand</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-zustand   // 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</h4>\n<p>Toteuta sitten sovellukseen koko sen varsinainen toiminnallisuus. </p>\n<p>Sovelluksesi ulkonäkö ja toiminnallisuus on sama kuin osassa 1:</p>\n<picture><img src=\"/static/a74acccc17aafb02b3801ffa1fcc0fdc/5a190/16e.png\" srcset=\"/static/a74acccc17aafb02b3801ffa1fcc0fdc/772e8/16e.png 200w,\n/static/a74acccc17aafb02b3801ffa1fcc0fdc/e17e5/16e.png 400w,\n/static/a74acccc17aafb02b3801ffa1fcc0fdc/5a190/16e.png 800w,\n/static/a74acccc17aafb02b3801ffa1fcc0fdc/c1b63/16e.png 1200w,\n/static/a74acccc17aafb02b3801ffa1fcc0fdc/c65fa/16e.png 1434w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n</div>\n<div class=\"content\">\n<h3>Zustand-muistiinpanot</h3>\n<p>Tavoitteenamme on tehdä vanhasta kunnon muistiinpanosovelluksesta Zustandia käyttävä versio.</p>\n<p>Sovelluksen ensimmäinen versio on seuraava. Komponentti <i>App</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> useNotes <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</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\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useNotes</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>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>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>important <span class=\"token operator\">?</span> <span class=\"token operator\">&lt;</span>strong<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>strong<span class=\"token operator\">></span> <span class=\"token operator\">:</span> note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</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<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> App</code></pre></div>\n<p>Store 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\">import</span> <span class=\"token punctuation\">{</span> create <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'zustand'</span>\n\n<span class=\"token keyword\">const</span> useNoteStore <span class=\"token operator\">=</span> <span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token keyword\">set</span></span> <span class=\"token operator\">=></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> <span class=\"token punctuation\">[</span>\n    <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 literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'Zustand is less complex than Redux'</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 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><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\">useNotes</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\">useNoteStore</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>Toistaiseksi sovelluksessa ei siis ole toiminnallisuutta uusien muistiinpanojen lisäämiseen, myöskään store ei vielä sitä tue. Tila on alustettu siten, että sinne on lisätty jo yksi muistiinpano jotta voimme varmistua, että sovellus onnistuu renderöimään tilan.</p>\n<h3>Puhtaat funktiot ja muuttumattomat (immutable) oliot</h3>\n<p>Ensimmäinen yritys muistiinpanon lisäävästsä actionista on seuraava:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token function\">set</span><span class=\"token punctuation\">(</span>\n          <span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">)</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>Funktio saa parametrikseen muistiinpanon, ja palauttaa tilan, missä vanhaan tilaan <i>state</i> on lisätty uusi muistiinpano.</p>\n<p>Yrityksemme on kuitenkin sääntöjen vastainen. Zustandin <a href=\"https://zustand.docs.pmnd.rs/learn/guides/immutable-state-and-merging\">dokumentaatio</a> toteaa <i>Like with React's useState, we need to update state immutably</i>, Kuten tiedämme <i>state.notes.push</i> muuttaa tila olion tilaa, eli ratkaisu ei kelpaa.</p>\n<p>Oikeaoppinen tapa on käyttää esimerkiksi <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat\">Array.concat</a> funktiota, joka ei muuta olemassaolevaa tilaa, vaan luo siitä uuden kopion, johon uusi muistiinpano on lisätty:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token function\">set</span><span class=\"token punctuation\">(</span>\n          <span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">concat</span><span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n          <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">)</span></code></pre></div>\n<p>Kokonaisuudessaan storen määrittely näyttää nyt seuraavalta</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> create <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'zustand'</span>\n\n<span class=\"token keyword\">const</span> useNoteStore <span class=\"token operator\">=</span> <span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token keyword\">set</span></span> <span class=\"token operator\">=></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> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">actions</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function-variable function\">add</span><span class=\"token operator\">:</span> <span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token function\">set</span><span class=\"token punctuation\">(</span>\n      <span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">concat</span><span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">)</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><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\">useNotes</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\">useNoteStore</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>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">useNoteActions</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\">useNoteStore</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> state<span class=\"token punctuation\">.</span>actions<span class=\"token punctuation\">)</span></code></pre></div>\n<blockquote>\n<h4>Array spread -syntaksi</h4>\n<p>Toinen usein nähty tapa hoitaa sama asia on käyttää taulukkojen <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax\">spread</a> -syntaksia:</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> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">,</span> note<span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Tässä siis muodostetaan taulukko, johon otetaan spread-syntaksilla jokainen taulukon <i>state.notes</i> alkioista sekä lisätään vielä loppuun uusi muistiinpano <i>notes</i>. On makuasia käyttääkö spreadia vai funktiota <i>concat</i>.</p>\n</blockquote>\n<p>Teknisesti ilmaisten Zustandilla muodostettu tila on <a href=\"https://developer.mozilla.org/en-US/docs/Glossary/Immutable\">muuttumaton (engl. immutable)</a>, ja tilaa muuttavien action-funktioiden 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<h3>Ei-kontrolloitu lomake</h3>\n<p>Lisätään sovellukseen mahdollisuus uusien muistiinpanojen tekemiseen:</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> useNotes<span class=\"token punctuation\">,</span> useNoteActions <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</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\">const</span> notes <span class=\"token operator\">=</span> <span class=\"token function\">useNotes</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> add <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useNoteActions</span><span class=\"token punctuation\">(</span><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\">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=\"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 punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    e<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> e<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\">    <span class=\"token function\">add</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <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> 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><span class=\"gatsby-highlight-code-line\">    e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span><span class=\"token function\">reset</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=\"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>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>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>important <span class=\"token operator\">?</span> <span class=\"token operator\">&lt;</span>strong<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>strong<span class=\"token operator\">></span> <span class=\"token operator\">:</span> note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</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></code></pre></div>\n<p>Toteutus on melko suoraviivainen. 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://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components\">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 esim. <a href=\"https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/\">täältä</a>.</p>\n</blockquote>\n<p>Lomake on erittäin yksinkertainen:</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=\"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></code></pre></div>\n<p>Huomioinarvoista lomakkeessa on se, että syötekentällä on nimi. Tämän ansiosta käsittelijäfunktio pääsee kentän arvoon käsiksi.</p>\n<p>Lisäyksen käsittelijä on sekin suoraviivainen</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\">addNote</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    e<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> e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>note<span class=\"token punctuation\">.</span>value\n    <span class=\"token function\">add</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <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> 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>\n    e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span><span class=\"token function\">reset</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<p>Lomakkeen tekstikentästä haetaan sisältö <i>e.target.note.value</i> muuttujaan, jota käytetään parametrina muistiinpanon lisäysfunktion <i>add</i> kutsussa. </p>\n<p>Viimeinen rivi eli, eli <i>e.target.reset()</i> tyhjentää lomakkeen.</p>\n<p>Sovelluksen tämänhetkinen koodi on kokonaisuudessaan <a href=\"https://github.com/fullstack-hy2020/zustand-notes/tree/part6-1\">GitHubissa</a>, branchissa <i>part6-1</i>.</p>\n<h3>Lisää komponentteja ja toiminnallisuutta</h3>\n<p>Jaetaan sovellus useampaan komponenttiin. Eriytetään uuden muistiinpanon luominen, muistiinpanojen lista sekä yksittäisen muistiinpanon esittäminen omiksi komponenteikseen.</p>\n<p>Komponentti <i>App</i> on muutoksen jälkeen 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\">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 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>NoteList <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></code></pre></div>\n<p>Muistiinpanon luominen eli <i>NoteForm</i> ei sisällä mitään dramaattista, ei toisteta sen koodia täällä.</p>\n<p>Muistiinpanojen listaamisesta vastaava komponentti <i>NoteList</i> 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> <span class=\"token punctuation\">{</span> useNotes <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</span>\n<span class=\"token keyword\">import</span> Note <span class=\"token keyword\">from</span> <span class=\"token string\">'./Note'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">NoteList</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> notes <span class=\"token operator\">=</span> <span class=\"token function\">useNotes</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>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 key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span> note<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">}</span> <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>Komponentti siis hakee storesta muistiinpanojen listan, ja luo jokaista vastaavan <i>Note</i> komponentin, jolle se välittää muistiinpanon tiedot propsina:</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\">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></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n  <span class=\"token operator\">&lt;</span>li<span class=\"token operator\">></span>\n    <span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>important <span class=\"token operator\">?</span> <span class=\"token operator\">&lt;</span>strong<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>strong<span class=\"token operator\">></span> <span class=\"token operator\">:</span> note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</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></code></pre></div>\n<p>Lisätään vielä sovellukseen mahdollisuus muistiinpanon tärkeyden muuttamiseen. Komponentti on muutoksen jälkeen 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> useNoteActions <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./store'</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></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 punctuation\">{</span> toggleImportance <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useNoteActions</span><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>li<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>important <span class=\"token operator\">?</span> <span class=\"token operator\">&lt;</span>strong<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>strong<span class=\"token operator\">></span> <span class=\"token operator\">:</span> note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span>\n<span class=\"gatsby-highlight-code-line\">      <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> <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=\"gatsby-highlight-code-line\">        <span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>important <span class=\"token operator\">?</span> <span class=\"token string\">'make not important'</span> <span class=\"token operator\">:</span> <span class=\"token string\">'make important'</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span></span>    <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></code></pre></div>\n<p>Komponentti destrukturoi funktion <i>useNoteActions</i> paluuarvosta tärkeyden muuttavan funktion, jota se kutsuu muutosnappia klikatessa.</p>\n<p>Tärkeyden muuttavan funktion toteutus 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> <span class=\"token punctuation\">{</span> create <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'zustand'</span>\n\n<span class=\"token keyword\">const</span> useNoteStore <span class=\"token operator\">=</span> <span class=\"token function\">create</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token keyword\">set</span></span> <span class=\"token operator\">=></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> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">actions</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function-variable function\">add</span><span class=\"token operator\">:</span> <span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token function\">set</span><span class=\"token punctuation\">(</span>\n      <span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">notes</span><span class=\"token operator\">:</span> state<span class=\"token punctuation\">.</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">concat</span><span class=\"token punctuation\">(</span>note<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=\"gatsby-highlight-code-line\">    <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 function\">set</span><span class=\"token punctuation\">(</span></span><span class=\"gatsby-highlight-code-line\">      <span class=\"token parameter\">state</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</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> state<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><span class=\"gatsby-highlight-code-line\">          note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> id <span class=\"token operator\">?</span> <span class=\"token punctuation\">{</span> <span class=\"token operator\">...</span>note<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>note<span class=\"token punctuation\">.</span>important <span class=\"token punctuation\">}</span> <span class=\"token operator\">:</span> note</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>  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Funktio siis saa parametrikseen muutettavan muistiinpanon id:n. Uusi tila muodostetaan vanhan perusteella funktion <i>map</i> avulla siten, että mukaan otetaan kaikki vanhat\nmuistiinpanot, paitsi muutettavasta muistiinpanosta tehdään versio, jossa sen tärkeys muuttuu päinvastaiseksi:</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>note<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">important</span><span class=\"token operator\">:</span> <span class=\"token operator\">!</span>note<span class=\"token punctuation\">.</span>important <span class=\"token punctuation\">}</span> </code></pre></div>\n<p>Sovelluksen tämänhetkinen koodi on kokonaisuudessaan <a href=\"https://github.com/fullstack-hy2020/zustand-notes/tree/part6-2\">GitHubissa</a>, branchissa <i>part6-2</i>.</p>\n</div>\n<div class=\"tasks\">\n<h3>Tehtävät 6.2.-6.6.</h3>\n<p>Toteutetaan uusi versio ensimmäisen osan anekdoottien äänestyssovelluksesta. Ota ratkaisusi pohjaksi repositoriossa <a href=\"https://github.com/fullstack-hy2020/zustand-anecdotes\">https://github.com/fullstack-hy2020/zustand-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> zustand-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/f7c8523c5a52273708ce11b1efcc9723/5a190/u2.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/f7c8523c5a52273708ce11b1efcc9723/772e8/u2.png 200w,\n/static/f7c8523c5a52273708ce11b1efcc9723/e17e5/u2.png 400w,\n/static/f7c8523c5a52273708ce11b1efcc9723/5a190/u2.png 800w,\n/static/f7c8523c5a52273708ce11b1efcc9723/c1b63/u2.png 1200w,\n/static/f7c8523c5a52273708ce11b1efcc9723/c8ad9/u2.png 1564w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<h4>6.2: anekdootit, step1</h4>\n<p>Toteuta mahdollisuus anekdoottien äänestämiseen. Äänien määrä tulee tallettaa Zustand-storeen.</p>\n<h4>6.3: 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_zustand#ei-kontrolloitu-lomake\">ei-kontrolloituna</a>.</p>\n<h4>6.4: anekdootit, step3</h4>\n<p>Eriytä uuden anekdootin luominen omaksi komponentikseen nimeltään <i>AnecdoteForm</i> ja Eriytä anekdoottilistan näyttäminen omaksi komponentikseen nimeltään <i>AnecdoteList</i>.</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>AnecdoteList <span class=\"token operator\">/</span><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><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<h4>6.5: anekdootit, step4</h4>\n<p>Huolehdi siitä, että anekdootit pysyvät äänten mukaisessa suuruusjärjestyksessä.</p>\n<p><strong>HUOM</strong> tässä tehtävässä kannattanee hyödyntää funktiota <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toSorted\">Array.toSorted</a>, joka ei järjestä alkuperäistä taulukkoa vaan luo siitä järjestetyn kopion. Tämä sen takia, että Zustand-tilaa ei saa muuttaa!</p>\n</div>","frontmatter":{"mainImage":{"publicURL":"/static/a3b7bc3fafcb5b47227616e1343970e5/part-6.svg"},"part":6,"letter":"a","lang":"fi"}}},"pageContext":{"part":6,"letter":"a","lang":"fi"}},"staticQueryHashes":["3128451518"]}