{"id":233548,"date":"2023-02-17T10:43:00","date_gmt":"2023-02-17T07:43:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=233548"},"modified":"2022-11-11T00:17:11","modified_gmt":"2022-11-10T21:17:11","slug":"luo-mukautettu-gutenberg-block-osa-7-luo-omia-mukautettuja-komponentteja","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/fi\/luo-mukautettu-gutenberg-block-osa-7-luo-omia-mukautettuja-komponentteja\/","title":{"rendered":"Luo mukautettu Gutenberg Block &#8211; Osa 7: Luo omia mukautettuja komponentteja"},"content":{"rendered":"\n<p>T\u00e4h\u00e4n menness\u00e4 t\u00e4ss\u00e4 opetusohjelmasarjassa olemme kirjoittaneet kaiken koodin funktion sis\u00e4\u00e4n <code>registerBlockType()<\/code>. <code>edit<\/code>Se on t\u00e4ysin mahdollista ja usein suositeltavaa m\u00e4\u00e4ritt\u00e4\u00e4 muokkaus erilliseen komponenttiin. N\u00e4in voimme hy\u00f6dynt\u00e4\u00e4 toimintoja, kuten komponenttien tila- ja elinkaarimenetelmi\u00e4. Se on my\u00f6s paljon puhtaampi, luettavampi ja tarjoaa uudelleenk\u00e4ytett\u00e4v\u00e4n koodin!<\/p>\n<p>Jos et ole perehtynyt React-komponenttien luomiseen tai mit\u00e4 tila- ja elinkaarimenetelm\u00e4t ovat, suosittelen lukemaan ensin <a href=\"https:\/\/reactjs.org\/docs\/state-and-lifecycle.html\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Reactin virallisen oppaan t\u00e4st\u00e4 aiheesta<\/a>.<\/p>\n<h2>Luokkakomponentin m\u00e4\u00e4ritt\u00e4minen kohteelle<code>edit<\/code><\/h2>\n<p>Voit m\u00e4\u00e4ritt\u00e4\u00e4 komponentin joko funktiona tai luokkana. Luokkakomponentilla voit k\u00e4ytt\u00e4\u00e4 toimintoja, kuten esimerkiksi tila- ja elinkaarimenetelmi\u00e4. Kuitenkin uudemmissa React-versioissa (16+) voit k\u00e4ytt\u00e4\u00e4 React-koukkuja tila- ja elinkaarimenetelmien simulointiin toimintokomponenttien sis\u00e4ll\u00e4. Mutta t\u00e4ss\u00e4 opetusohjelmassa keskitymme luokkakomponentin luomiseen. Se, mit\u00e4 olemme t\u00e4h\u00e4n menness\u00e4 luoneet t\u00e4ss\u00e4 sarjassa, &quot;inline&quot; <code>registerBlockType()<\/code>for <code>edit<\/code>ja <code>save<\/code>, ovat funktiokomponentteja.<\/p>\n<p>Luokkakomponentin m\u00e4\u00e4ritt\u00e4mist\u00e4 varten laajennamme WordPressin <code>Component<\/code>( <code>wp.element<\/code>paketissa), aivan kuten laajennat luokkakomponentin kohtaan <code>React.Component<\/code>.<\/p>\n<p>Muista, ett\u00e4 luokkakomponenttisi tulee sis\u00e4lt\u00e4\u00e4 funktio <code>render()<\/code>. Ja koska Javascript toimii, luokkasi on m\u00e4\u00e4ritett\u00e4v\u00e4 ennen <code>registerBlockType()<\/code>kutsua (kirjoita luokkakomponentti ensin tiedostoon ja s\u00e4ilyt\u00e4 <code>registerBlockType()<\/code>sen j\u00e4lkeen. My\u00f6hemmin t\u00e4ss\u00e4 viestiss\u00e4 opimme erottamaan komponentit erillisiksi tiedostoiksi, viem\u00e4\u00e4n ja sis\u00e4llytt\u00e4m\u00e4\u00e4n niit\u00e4).<\/p>\n<p>Lyhyesti n\u00e4in:<\/p>\n<pre><code>const { registerBlockType } = wp.blocks;\nconst { Component } = wp.element;\n\u00a0\nclass FirstBlockEdit extends Component {\n    render() {\n        const { attributes, setAttributes } = this.props;\n        return ...\n    }\n}\n\u00a0\nregisterBlockType('awp\/firstblock', {\n    title: 'My first block',\n    edit: FirstBlockEdit,\n    save: (props) =&gt; { \n        return ...\n    }\n});<\/code><\/pre>\n<p>Rekvisiitta osoitteesta <code>edit<\/code>k\u00e4ytet\u00e4\u00e4n automaattisesti komponenttiimme. \u00c4l\u00e4 unohda, ett\u00e4 luokkakomponentti, johon sinun on viitattava rekvisiitta <code>this.props<\/code>. WordPress Gutenberg -ytimess\u00e4 on yleist\u00e4 k\u00e4ytt\u00e4\u00e4 erillisi\u00e4 komponentteja <code>edit<\/code>toimintoihin, koska ne sis\u00e4lt\u00e4v\u00e4t useimmiten paljon enemm\u00e4n koodia. Funktio <code>save<\/code>voidaan usein j\u00e4tt\u00e4\u00e4 sis\u00e4\u00e4n, <code>registerBlockType()<\/code>ellei siin\u00e4 ole my\u00f6s paljon koodia.<\/p>\n<p>Tekem\u00e4ll\u00e4 t\u00e4m\u00e4n voit nyt kirjoittaa komponentin aivan kuten kirjoittaisit Reactin kanssa. Voit lis\u00e4t\u00e4 toimintoja, rakentajia, tila- ja elinkaarimenetelmi\u00e4.<\/p>\n<p>T\u00e4m\u00e4 on koodi, jonka p\u00e4\u00e4dyimme viimeiseen vaiheeseen, muutettuna luokkakomponentiksi:<\/p>\n<pre><code>const { registerBlockType } = wp.blocks;\nconst { Component } = wp.element;\nconst { RichText, InspectorControls, BlockControls, AlignmentToolbar } = wp.blockEditor;\nconst { ToggleControl, PanelBody, PanelRow, CheckboxControl, SelectControl, ColorPicker, Toolbar, IconButton } = wp.components;\n\u00a0\nclass FirstBlockEdit extends Component {\n\u00a0\n    render() {\n        const { attributes, setAttributes } = this.props;\n        const alignmentClass = (attributes.textAlignment != null)? 'has-text-align-' + attributes.textAlignment: '';\n\u00a0\n        return (&lt;div className={alignmentClass}&gt;\n                &lt;InspectorControls&gt;\n                    &lt;PanelBody\n                        title=\"Most awesome settings ever\"\n                        initialOpen={true}\n                    &gt;\n                        &lt;PanelRow&gt;\n                            &lt;ToggleControl\n                                label=\"Toggle me\"\n                                checked={attributes.toggle}\n                                onChange={(newval) =&gt; setAttributes({ toggle: newval })}\n                            \/&gt;\n                        &lt;\/PanelRow&gt;\n                        &lt;PanelRow&gt;\n                            &lt;SelectControl\n                                label=\"What's your favorite animal?\"\n                                value={attributes.favoriteAnimal}\n                                options={[\n                                    {label: \"Dogs\", value: 'dogs'},\n                                    {label: \"Cats\", value: 'cats'},\n                                    {label: \"Something else\", value: 'weird_one'},\n                                ]}\n                                onChange={(newval) =&gt; setAttributes({ favoriteAnimal: newval })}\n                            \/&gt;\n                        &lt;\/PanelRow&gt;\n                        &lt;PanelRow&gt;\n                            &lt;ColorPicker\n                                color={attributes.favoriteColor}\n                                onChangeComplete={(newval) =&gt; setAttributes({ favoriteColor: newval.hex })}\n                                disableAlpha\n                            \/&gt;\n                        &lt;\/PanelRow&gt;\n                        &lt;PanelRow&gt;\n                            &lt;CheckboxControl\n                                label=\"Activate lasers?\"\n                                checked={attributes.activateLasers}\n                                onChange={(newval) =&gt; setAttributes({ activateLasers: newval })}\n                            \/&gt;\n                        &lt;\/PanelRow&gt;\n                    &lt;\/PanelBody&gt;\n                &lt;\/InspectorControls&gt;\n                &lt;BlockControls&gt;\n                    &lt;AlignmentToolbar\n                        value={attributes.textAlignment}\n                        onChange={(newalign) =&gt; setAttributes({ textAlignment: newalign })}\n                    \/&gt;\n                    &lt;Toolbar&gt;\n                        &lt;IconButton\n                            label=\"My very own custom button\"\n                            icon=\"edit\"\n                            className=\"my-custom-button\"\n                            onClick={() =&gt; console.log('pressed button')}\n                        \/&gt;\n                    &lt;\/Toolbar&gt;\n                &lt;\/BlockControls&gt;\n                &lt;RichText \n                    tagName=\"h2\"\n                    placeholder=\"Write your heading here\"\n                    value={attributes.myRichHeading}\n                    onChange={(newtext) =&gt; setAttributes({ myRichHeading: newtext })}\n                \/&gt;\n                &lt;RichText\n                    tagName=\"p\"\n                    placeholder=\"Write your paragraph here\"\n                    value={attributes.myRichText}\n                    onChange={(newtext) =&gt; setAttributes({ myRichText: newtext })}\n                \/&gt;\n            &lt;\/div&gt;\n        );\n    }\n}\n\u00a0\nregisterBlockType('awp\/firstblock', {\n    title: 'My first block',\n    category: 'common',\n    icon: 'smiley',\n    description: 'Learning in progress',\n    keywords: ['example', 'test'],\n    attributes: {\n        myRichHeading: {\n            type: 'string',\n        },\n        myRichText: {\n            type: 'string',\n            source: 'html',\n            selector: 'p'\n        },\n        textAlignment: {\n            type: 'string',\n        },\n        toggle: {\n            type: 'boolean',\n            default: true\n        },\n        favoriteAnimal: {\n            type: 'string',\n            default: 'dogs'\n        },\n        favoriteColor: {\n            type: 'string',\n            default: '#DDDDDD'\n        },\n        activateLasers: {\n            type: 'boolean',\n            default: false\n        },\n    },\n    supports: {\n        align: ['wide', 'full']\n    },\n    edit: FirstBlockEdit,\n    save: (props) =&gt; { \n        const { attributes } = props;\n\u00a0\n        const alignmentClass = (attributes.textAlignment != null)? 'has-text-align-' + attributes.textAlignment: '';\n\u00a0\n        return (&lt;div className={alignmentClass}&gt;\n                &lt;RichText.Content \n                    tagName=\"h2\"\n                    value={attributes.myRichHeading}\n                \/&gt;\n                &lt;RichText.Content \n                    tagName=\"p\"\n                    value={attributes.myRichText}\n                \/&gt;\n                {attributes.activateLasers &amp;&amp; \n                    &lt;div className=\"lasers\"&gt;Lasers activated&lt;\/div&gt;\n                }\n            &lt;\/div&gt;\n        );\n    }\n});<\/code><\/pre>\n<p>Jos destructered <code>attributes<\/code>ja <code>setAttributes<\/code>rekvisiitta, kuten me teimme, sinun tarvitsee vain muuttaa siirtyess\u00e4si erilliseen luokkakomponenttiin on yhden rivin vaihtaminen; <code>#9<\/code>alkaen <code>props<\/code>&#8211; <code>this.props<\/code>. Kaikki koodi toimii kuten ennenkin ilman korjauksia. Siin\u00e4 on tuhoamisen kauneus. Jos et tuhonnut sit\u00e4 ja viitannut esim. <code>props.attributes<\/code>suoraan, sinun on lis\u00e4tt\u00e4v\u00e4 <code>this.<\/code>kaikkien yksitt\u00e4isten viittausten eteen <code>attributes<\/code>ja <code>setAttributes<\/code>kaikkialle.<\/p>\n<p>Aloitetaan tekem\u00e4\u00e4n asioita, joita voimme nyt tehd\u00e4 luokkakomponentilla!<\/p>\n<h2>Toimintojen m\u00e4\u00e4rittely ja<code>this<\/code><\/h2>\n<p>Kyll\u00e4, voit m\u00e4\u00e4ritt\u00e4\u00e4 funktioita funktiokomponentin sis\u00e4lt\u00e4 <code>edit<\/code>ennen kutsumista <code>return<\/code>. Mutta henkil\u00f6kohtaisesti olen aina halunnut erottaa toiminnallisuuden logiikan mukaan. Minusta on parempi erottaa funktiot logiikkaa ja muita tarkoituksia varten tulosten hahmontamisesta vastaavan funktion ulkopuolella. Jotkut ihmiset my\u00f6s kutsuvat mieluummin toimintoja tapahtumissa sen sijaan, ett\u00e4 tekisiv\u00e4t ne inline-muodossa, kuten olemme tehneet t\u00e4h\u00e4n menness\u00e4 (<code>setAttributes()<\/code>esimerkiksi <code>onChange<\/code>).<\/p>\n<p>T\u00e4ll\u00e4 hetkell\u00e4 koodissamme on kaksi asiaa, jotka voisivat olla hy\u00f6dyllisi\u00e4 siirrett\u00e4ess\u00e4 toimintoihin; <code>InspectorControls<\/code>ja <code>BlockControls<\/code>. T\u00e4m\u00e4 lyhent\u00e4\u00e4 <code>return<\/code>huomattavasti ja helpottaa koodin lukemista.<\/p>\n<p>M\u00e4\u00e4rittelemme kaksi funktiota, jotka palauttavat koko <code>InspectorControls<\/code>lohkon ja koko <code>BlockControls<\/code>lohkon. K\u00e4ytt\u00e4m\u00e4ll\u00e4 nuolitoimintoja (<code>functionName =() =&gt; { ... }<\/code>) meill\u00e4 on t\u00e4ysi p\u00e4\u00e4sy <code>this<\/code>rekvisiittaaksemme. Jos et suorittanut vaiheen 1 viimeist\u00e4 osaa \u2013 Babelin m\u00e4\u00e4ritt\u00e4minen uusimmilla syntakseilla, saat k\u00e4\u00e4nn\u00f6svirheit\u00e4. Sinun on luotava rakentaja ja sidonta <code>this<\/code>jokaiselle funktiolle. Voit lukea lis\u00e4\u00e4 k\u00e4sittelyst\u00e4 <a href=\"https:\/\/reactjs.org\/docs\/faq-functions.html\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Reactin UKK-sivun<\/a><code>this<\/code> alussa .<a href=\"https:\/\/reactjs.org\/docs\/faq-functions.html\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external\"><\/a><\/p>\n<p>Muista my\u00f6s, ett\u00e4 koska olemme nyt luokassa, sinun on kutsuttava kaikki sen funktiot <code>this.<\/code>edess\u00e4.<\/p>\n<pre><code>class FirstBlockEdit extends Component {\n\u00a0\n    getInspectorControls =() =&gt; {\n        const { attributes, setAttributes } = this.props;\n\u00a0\n        return (&lt;InspectorControls&gt;\n                ...\n            &lt;\/InspectorControls&gt;\n        );\n    }\n\u00a0\n    getBlockControls = () =&gt; {\n        const { attributes, setAttributes } = this.props;\n\u00a0\n        return (&lt;BlockControls&gt;\n                ...\n            &lt;\/BlockControls&gt;\n        );\n    }\n\u00a0\n    render() {\n        const { attributes, setAttributes } = this.props;\n        const alignmentClass = (attributes.textAlignment != null)? 'has-text-align-' + attributes.textAlignment: '';\n\u00a0\n        return ([\n            this.getInspectorControls(),\n            this.getBlockControls(),\n            &lt;div className={alignmentClass}&gt;\n                &lt;RichText \n                    tagName=\"h2\"\n                    placeholder=\"Write your heading here\"\n                    value={attributes.myRichHeading}\n                    onChange={(newtext) =&gt; setAttributes({ myRichHeading: newtext })}\n                \/&gt;\n                &lt;RichText\n                    tagName=\"p\"\n                    placeholder=\"Write your paragraph here\"\n                    value={attributes.myRichText}\n                    onChange={(newtext) =&gt; setAttributes({ myRichText: newtext })}\n                \/&gt;\n            &lt;\/div&gt;\n        ]);\n    }\n}<\/code><\/pre>\n<p>Huomaa, ett\u00e4 olen j\u00e4tt\u00e4nyt pois koodin todellisen sis\u00e4ll\u00f6n <code>InspectorControls<\/code>ja <code>BlockControls<\/code>pit\u00e4\u00e4kseni koodin lyhyemp\u00e4n\u00e4. Mik\u00e4\u00e4n heid\u00e4n koodissaan ei tarvitse muuttua.<\/p>\n<p>Hy\u00f6dynn\u00e4mme my\u00f6s sit\u00e4, ett\u00e4 <code>return<\/code>lauseke voi palauttaa my\u00f6s taulukon. Kaikki taulukossa oleva hahmonnetaan tavalliseen tapaan siin\u00e4 j\u00e4rjestyksess\u00e4, jossa ne ovat. T\u00e4m\u00e4n ansiosta meid\u00e4n on helppo kutsua funktioita suoraan <code>return<\/code>k\u00e4skyn sis\u00e4ll\u00e4.<\/p>\n<p>Voit tietysti m\u00e4\u00e4ritell\u00e4 my\u00f6s elinkaarimenetelmi\u00e4, kuten <code>componentDidMount()<\/code>. N\u00e4iden tekemisess\u00e4 ei ole mit\u00e4\u00e4n eroa Gutenberg-komponenteissa kuin Reactissa.<\/p>\n<h2>Rakentaja ja k\u00e4ytt\u00f6tila<\/h2>\n<p>Yritet\u00e4\u00e4n toteuttaa tila komponenttiimme. Muista, ett\u00e4 tila on vain jotain, joka on tallennettu tilap\u00e4isesti luokkakomponenttiimme, eik\u00e4 sit\u00e4 tallenneta mihink\u00e4\u00e4n \u2013 kuten attribuutteihin. Se on vain komponentin tilan hallintaan. Yleisi\u00e4 tilan k\u00e4ytt\u00f6j\u00e4 ovat tilan k\u00e4ytt\u00f6 tilalippuna odottaessaan asynkronisen kutsun paluuta, jonkin pistem\u00e4\u00e4r\u00e4n s\u00e4ilytt\u00e4minen v\u00e4liaikaisesti ennen sen tallentamista attribuutissa tai lohkon &quot;esikatselu\/muokkaustila&quot; k\u00e4ytt\u00f6\u00f6notto.<\/p>\n<p>Viittaat tilaan ja p\u00e4ivitystilaan kuten Reactissa; <code>this.state<\/code>ja <code>setState()<\/code>. _ Normaalisti alustat tilan konstruktorissa. Ja mit\u00e4 tulee rakentajan m\u00e4\u00e4rittelyyn \u2013 se on aivan kuten Reactissa \u2013 \u00e4l\u00e4 unohda l\u00e4p\u00e4ist\u00e4 <code>props<\/code>ja tehd\u00e4 <code>super(props)<\/code>samoin. Lyhyesti:<\/p>\n<pre><code>class FirstBlockEdit extends Component {\n    constructor(props) {\n        super(props);\n\u00a0\n        this.state = {\n            example: 1\n        }\n    }\n\u00a0\n    render() {\n        this.setState({ example: 2 });\n        console.log(this.state.example);\n        ...<\/code><\/pre>\n<h3>Est\u00e4-tilan muokkaus-\/esikatselukytkin<\/h3>\n<p>Luodaan &quot;tilanvaihtaja&quot; lohkollemme edellisess\u00e4 ty\u00f6kalupalkissa opittuja asioita. Otamme k\u00e4ytt\u00f6\u00f6n ty\u00f6kalupalkin, jossa on painike, joka vaihtaa tilaa esikatselu- ja muokkaustilan v\u00e4lill\u00e4. Muokkaustilassa lohko saa kaksi RichText-komponenttia tavalliseen tapaan. Mutta kun siirryimme esikatselutilaan, otimme muokkauksen pois p\u00e4\u00e4lt\u00e4 ja render\u00f6imme lohkotulosteen.<\/p>\n<p>Ensin luodaan konstruktori ja asetetaan tila yhdell\u00e4 boolen ominaisuudella; <code>editMode<\/code>joka alkaa nimell\u00e4 <code>true<\/code>. Se <code>super(props)<\/code>on v\u00e4ltt\u00e4m\u00e4t\u00f6n m\u00e4\u00e4ritett\u00e4ess\u00e4 konstruktoria luokkapohjaisessa React-komponentissa.<\/p>\n<pre><code>class FirstBlockEdit extends Component {\n    constructor(props) {\n        super(props);\n        this.state = {\n            editMode: true\n        }\n    }\n    ...<\/code><\/pre>\n<p>Ty\u00f6kalurivien tulostamistoiminnossa muutamme aiemmin luomaamme mukautettua painiketta (joka vain <code>console.log<\/code>jotain sit\u00e4 napsauttaessa). Sen <code>onClick<\/code>propessa kutsumme <code>setState()<\/code>ja kumoamme nykyisen <code>editMode<\/code>loogisen arvon. Jotta k\u00e4ytt\u00e4j\u00e4n olisi helpompi ymm\u00e4rt\u00e4\u00e4, vaihdamme my\u00f6s painikkeen kuvakkeen ja tunnisteen v\u00e4lill\u00e4. Esimerkiksi kun esikatselutila on aktiivinen, painikkeessa n\u00e4kyy otsikko &quot;Muokkaa&quot; ja kyn\u00e4kuvake, joka on yleisesti hyv\u00e4ksytty muokkaukseksi.<\/p>\n<pre><code>getBlockControls = () =&gt; {\n    const { attributes, setAttributes } = this.props;\n    return (&lt;BlockControls&gt;\n            &lt;AlignmentToolbar\n                value={attributes.textAlignment}\n                onChange={(newalign) =&gt; setAttributes({ textAlignment: newalign })}\n            \/&gt;\n            &lt;Toolbar&gt;\n                &lt;IconButton\n                    label={ this.state.editMode? \"Preview\": \"Edit\" }\n                    icon={ this.state.editMode? \"format-image\": \"edit\" }\n                    onClick={() =&gt; this.setState({ editMode: !this.state.editMode })}\n                \/&gt;\n            &lt;\/Toolbar&gt;\n        &lt;\/BlockControls&gt;\n    );\n}<\/code><\/pre>\n<p>Ja lopuksi lohkomme p\u00e4\u00e4render\u00f6intimenetelm\u00e4n sis\u00e4ll\u00e4 voimme tehd\u00e4 mit\u00e4 haluamme. T\u00e4m\u00e4 osa on todella sinun p\u00e4\u00e4tett\u00e4viss\u00e4si \u2013 teet samoin kuin teimme yll\u00e4 olevan painikkeen etiketill\u00e4 ja kuvakkeella. Lis\u00e4\u00e4mme kaksi tulostelohkoa, yhden jos <code>this.state.editMode<\/code>on <code>true<\/code>(jonka pit\u00e4isi olla tavallisia muokattavia <code>RichText<\/code>komponentteja) ja toisen jos se on <code>false<\/code>.<\/p>\n<p>Esimerkkin\u00e4 k\u00e4yt\u00e4n kahta WordPress-komponenttia <code>wp.components<\/code>; <code>Placeholder<\/code>ja <code>Disabled<\/code>esikatselutilaa varten. Komponentti <code>Placeholder<\/code>laittaa lohkosi mukavaan harmaaseen laatikkoon, mik\u00e4 tekee todella selv\u00e4ksi, ett\u00e4 sit\u00e4 ei voi muokata. Muista, ett\u00e4 se on liitetty muotoiluun, joten jos haluat t\u00e4ydellisen esikatselun, t\u00e4m\u00e4 ei ehk\u00e4 ole sinua varten. Ja k\u00e4\u00e4rin kaiken my\u00f6s <code>Disabled<\/code>komponentin sis\u00e4\u00e4n, mik\u00e4 tekee kaikesta sis\u00e4lt\u00e4 ei-muokattavissa, ei napsautettavaa ja vedett\u00e4viss\u00e4. T\u00e4m\u00e4 on uusi <code>render()<\/code>toimintomme komponentissamme:<\/p>\n<pre><code>const { ..., Fragment } = wp.element;\nconst {... Placeholder, Disabled } = wp.components;  \/\/ Don't forget to add these at the top\n\u00a0\n...\nrender() {\n    const { attributes, setAttributes } = this.props;\n    const alignmentClass = (attributes.textAlignment != null)? 'has-text-align-' + attributes.textAlignment: '';\n\u00a0\n    return ([\n        this.getInspectorControls(),\n        this.getBlockControls(),\n        &lt;div className={alignmentClass}&gt;\n            {this.state.editMode &amp;&amp; \n                &lt;Fragment&gt;\n                    &lt;RichText \n                        tagName=\"h2\"\n                        placeholder=\"Write your heading here\"\n                        value={attributes.myRichHeading}\n                        onChange={(newtext) =&gt; setAttributes({ myRichHeading: newtext })}\n                    \/&gt;\n                    &lt;RichText\n                        tagName=\"p\"\n                        placeholder=\"Write your paragraph here\"\n                        value={attributes.myRichText}\n                        onChange={(newtext) =&gt; setAttributes({ myRichText: newtext })}\n                    \/&gt;\n                &lt;\/Fragment&gt;\n            }\n            {!this.state.editMode &amp;&amp; \n                &lt;Placeholder isColumnLayout={true}&gt;\n                    &lt;Disabled&gt;\n                        &lt;RichText.Content \n                            tagName=\"h2\"\n                            value={attributes.myRichHeading}\n                        \/&gt;\n                        &lt;RichText.Content\n                            tagName=\"p\"\n                            value={attributes.myRichText}\n                        \/&gt;\n                    &lt;\/Disabled&gt;\n                &lt;\/Placeholder&gt;\n            }\n        &lt;\/div&gt;\n    ]);\n}\n...<\/code><\/pre>\n<p>K\u00e4yt\u00e4n my\u00f6s komponenttia <code>Fragment<\/code>( <code>wp.element<\/code>pakettia), joka on sama kuin <code>React.Fragment<\/code>. Jos et tunne sit\u00e4, k\u00e4\u00e4rimme tulosteen sen sis\u00e4\u00e4n, kun emme halua lis\u00e4t\u00e4 ylim\u00e4\u00e4r\u00e4isi\u00e4 tarpeettomia HTML-k\u00e4\u00e4reit\u00e4. Reactissa kaikella on oltava juurisolmu. Kun muokkaustila on aktiivinen (rivi <code>#13<\/code>), tulostamme kaksi <code>RichText<\/code>komponenttia heti per\u00e4kk\u00e4in, joten tarvitsemme juurisolmun niiden ymp\u00e4rille.<\/p>\n<p>Kun esikatselutila on aktiivinen (rivi <code>#29<\/code>), tulostamme kahden <code>RichText<\/code>komponentin arvot. Kuten <code>save<\/code>sovelluksessa, k\u00e4yt\u00e4mme <code>RichText.Content<\/code>palauttamaan niiden arvot pienen editorin sijaan.<\/p>\n<p>Komponentti <code>Placeholder<\/code>tulee joustavalla tyylill\u00e4 ja oletuksena flex-direction-rivill\u00e4. Tarjoaminen <code>true<\/code>potkurissa <code>isColumnLayout<\/code>muuttaa sen flex-direction-sarakkeeksi (joten kaikki pinoutuu). Mutta kuten aiemmin mainittiin &#8211; saatat haluta ohittaa t\u00e4m\u00e4n komponentin ja luoda esikatselun t\u00e4sm\u00e4lleen samalla tavalla kuin se olisi k\u00e4ytt\u00f6liittym\u00e4ss\u00e4.<\/p>\n<p>Ja sill\u00e4 meill\u00e4 on estotilan esikatselu\/muokkauskytkin. Ilmeisesti voit s\u00e4\u00e4t\u00e4\u00e4 &quot;edit mode&quot; -tilan sis\u00e4lt\u00f6\u00e4 n\u00e4ytt\u00e4m\u00e4\u00e4n esim. ohjaustulot tai mit\u00e4 muuta.<\/p>\n<\/p>\n<p>Voit luoda niin monta komponenttia kuin haluat, et rajoita vain yhden <code>edit<\/code>toimintoon! Luo vain lis\u00e4\u00e4 komponentteja ja sis\u00e4llyt\u00e4 ne <code>return<\/code>lauseeseen. Se on itse asiassa Reactin idea \u2013 rakentaa kapseloituja koodinp\u00e4tki\u00e4, joista kukin mahdollisesti k\u00e4sittelee omaa tilaansa ja yhdist\u00e4\u00e4 ne monimutkaiseksi k\u00e4ytt\u00f6liittym\u00e4ksi.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/awhitepixel.com\" class=\"external external_icon\">awhitepixel.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>T\u00e4ss\u00e4 Gutenberg-lohkoopetusohjelman osassa opimme siirt\u00e4m\u00e4\u00e4n registerBlockTypen muokkaustoiminnon erilliseen luokkapohjaiseen komponenttiin.<\/p>\n","protected":false},"author":1,"featured_media":152941,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[895,719,938,938,719,895,1110,834,843,803,803,834,843,864,864],"tags":[1166],"class_list":{"0":"post-233548","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","6":"hentry","7":"category-koodi","8":"category-kehittaejae","9":"category-gutenberg-5","13":"category-n-a","14":"category-opas-aloittelijoille","15":"category-opetusohjelmia","16":"category-php-5","20":"category-wordpress-5","22":"tag-affiai-fi"},"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/posts\/233548","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/comments?post=233548"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/posts\/233548\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/media\/152941"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/media?parent=233548"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/categories?post=233548"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/fi\/wp-json\/wp\/v2\/tags?post=233548"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}