{"id":233553,"date":"2023-02-17T10:38:00","date_gmt":"2023-02-17T07:38:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=233553"},"modified":"2022-11-11T00:18:40","modified_gmt":"2022-11-10T21:18:40","slug":"utworz-niestandardowy-blok-gutenberga-czesc-7-utworz-wlasne-niestandardowe-komponenty","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/utworz-niestandardowy-blok-gutenberga-czesc-7-utworz-wlasne-niestandardowe-komponenty\/","title":{"rendered":"Utw\u00f3rz niestandardowy blok Gutenberga &#8211; Cz\u0119\u015b\u0107 7: Utw\u00f3rz w\u0142asne niestandardowe komponenty"},"content":{"rendered":"\n<p>Jak dot\u0105d w tej serii samouczk\u00f3w napisali\u015bmy ca\u0142y kod wewn\u0105trz <code>registerBlockType()<\/code>funkcji <code>edit<\/code>. Jest to w pe\u0142ni mo\u017cliwe i cz\u0119sto zalecane, aby zamiast tego przypisa\u0107 edycj\u0119 do oddzielnego komponentu. W ten spos\u00f3b mo\u017cemy wykorzysta\u0107 funkcje, takie jak stan komponent\u00f3w i metody cyklu \u017cycia. Jest r\u00f3wnie\u017c znacznie czystszy, czytelny i zapewnia kod wielokrotnego u\u017cytku!<\/p>\n<p>Je\u015bli nie jeste\u015b zaznajomiony z tworzeniem komponent\u00f3w React lub czym s\u0105 metody stanu i cyklu \u017cycia, polecam najpierw zapozna\u0107 <a href=\"https:\/\/reactjs.org\/docs\/state-and-lifecycle.html\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">si\u0119 z oficjalnym przewodnikiem Reacta na ten temat<\/a>.<\/p>\n<h2>Definiowanie komponentu klasy dla<code>edit<\/code><\/h2>\n<p>Komponent mo\u017cna zdefiniowa\u0107 jako funkcj\u0119 lub klas\u0119. Dzi\u0119ki komponentowi klasy mo\u017cesz korzysta\u0107 z funkcjonalno\u015bci, takich jak na przyk\u0142ad metody stanu i cyklu \u017cycia. Jednak w nowszych wersjach Reacta (16+) mo\u017cesz u\u017cy\u0107 hook\u00f3w Reacta do symulacji stanu i metod cyklu \u017cycia wewn\u0105trz komponent\u00f3w funkcyjnych. Ale w tym samouczku skupimy si\u0119 na tworzeniu komponentu klasy. To, co do tej pory stworzyli\u015bmy w tej serii, \u201einline&quot; w <code>registerBlockType()<\/code>for <code>edit<\/code>i <code>save<\/code>, to komponenty funkcyjne.<\/p>\n<p>Aby zdefiniowa\u0107 komponent klasy, rozszerzamy WordPress&#8217; <code>Component<\/code>(w <code>wp.element<\/code>pakiecie), dok\u0142adnie tak, jak rozszerzasz komponent klasy do <code>React.Component<\/code>.<\/p>\n<p>Pami\u0119taj, \u017ce komponent klasy musi zawiera\u0107 funkcj\u0119 <code>render()<\/code>. A ze wzgl\u0119du na to, jak dzia\u0142a JavaScript, Twoja klasa musi by\u0107 zdefiniowana przed <code>registerBlockType()<\/code>wywo\u0142aniem (najpierw zapisz sw\u00f3j komponent klasy w pliku i zachowaj <code>registerBlockType()<\/code>go. P\u00f3\u017aniej w tym po\u015bcie nauczymy si\u0119 rozdziela\u0107 komponenty w osobnych plikach, eksportowa\u0107 i do\u0142\u0105cza\u0107 ich).<\/p>\n<p>W skr\u00f3cie tak:<\/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>Rekwizyty z <code>edit<\/code>s\u0105 automatycznie stosowane do naszego komponentu. Nie zapominaj, \u017ce komponent klasy musisz odwo\u0142a\u0107 si\u0119 do props za pomoc\u0105 <code>this.props<\/code>. W rdzeniu WordPress Gutenberg cz\u0119sto u\u017cywa si\u0119 oddzielnych komponent\u00f3w dla <code>edit<\/code>funkcji, poniewa\u017c najcz\u0119\u015bciej zawieraj\u0105 one znacznie wi\u0119cej kodu. Funkcj\u0119 <code>save<\/code>mo\u017cna cz\u0119sto pozostawi\u0107 <code>registerBlockType()<\/code>, chyba \u017ce zawiera r\u00f3wnie\u017c du\u017co kodu.<\/p>\n<p>Robi\u0105c to, mo\u017cesz teraz napisa\u0107 sw\u00f3j komponent, tak jak w przypadku Reacta. Mo\u017cesz dodawa\u0107 funkcje, konstruktora, metody stanu i cyklu \u017cycia.<\/p>\n<p>Oto kod, kt\u00f3ry znale\u017ali\u015bmy w ostatnim kroku, przekonwertowany na komponent klasy:<\/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>Je\u015bli zdestrukturyzowa\u0142e\u015b si\u0119 <code>attributes<\/code>z <code>setAttributes<\/code>rekwizyt\u00f3w, tak jak my, wszystko, co musisz zmieni\u0107, przechodz\u0105c do osobnego komponentu klasy, to zmiana jednej linii; <code>#9<\/code>od <code>props<\/code>do <code>this.props<\/code>. Ca\u0142y kod b\u0119dzie dzia\u0142a\u0142 tak jak poprzednio, bez naprawiania czegokolwiek innego. Na tym polega pi\u0119kno destrukturyzacji. Gdyby\u015b go nie zdestrukturyzowa\u0142 i nie odni\u00f3s\u0142 si\u0119 np <code>props.attributes<\/code>. bezpo\u015brednio, musia\u0142by\u015b doda\u0107 <code>this.<\/code>przed wszystkimi indywidualnymi odniesieniami do <code>attributes<\/code>i <code>setAttributes<\/code>wsz\u0119dzie.<\/p>\n<p>Zacznijmy robi\u0107 rzeczy, kt\u00f3re teraz mo\u017cemy zrobi\u0107 z komponentem klasy!<\/p>\n<h2>Definiowanie funkcji i<code>this<\/code><\/h2>\n<p>Oczywi\u015bcie tak, mo\u017cesz zdefiniowa\u0107 funkcje z <code>edit<\/code>komponentu funkcji, przed wywo\u0142aniem <code>return<\/code>. Ale osobi\u015bcie zawsze wola\u0142em rozdziela\u0107 funkcjonalno\u015b\u0107 wed\u0142ug logiki. Uwa\u017cam, \u017ce lepiej jest oddzieli\u0107 funkcje dla logiki i innych cel\u00f3w poza funkcj\u0105 odpowiedzialn\u0105 za renderowanie danych wyj\u015bciowych. Niekt\u00f3rzy ludzie wol\u0105 r\u00f3wnie\u017c wywo\u0142ywa\u0107 funkcje w zdarzeniach, zamiast robi\u0107 je w linii, tak jak robili\u015bmy to do tej pory (na przyk\u0142ad robi\u0105c <code>setAttributes()<\/code>) <code>onChange<\/code>.<\/p>\n<p>W tej chwili nasz kod ma dwie rzeczy, kt\u00f3re mog\u0105 by\u0107 korzystne, aby przej\u015b\u0107 do funkcji; <code>InspectorControls<\/code>i <code>BlockControls<\/code>. To znacznie skr\u00f3ci <code>return<\/code>nasz kod i sprawi, \u017ce nasz kod b\u0119dzie \u0142atwiejszy do odczytania.<\/p>\n<p>Definiujemy dwie funkcje, kt\u00f3re zwracaj\u0105 ca\u0142y <code>InspectorControls<\/code>blok i ca\u0142y <code>BlockControls<\/code>blok. U\u017cywaj\u0105c funkcji strza\u0142ek (<code>functionName =() =&gt; { ... }<\/code>) mamy pe\u0142ny dost\u0119p do <code>this<\/code>chwytania rekwizyt\u00f3w. Je\u015bli nie wykona\u0142e\u015b ostatniej cz\u0119\u015bci kroku 1 \u2013 konfiguracji Babel z najnowsz\u0105 sk\u0142adni\u0105, otrzymasz b\u0142\u0119dy kompilacji. Musia\u0142by\u015b uciec si\u0119 do stworzenia konstruktora i powi\u0105zania <code>this<\/code>dla ka\u017cdej funkcji. Mo\u017cesz przeczyta\u0107 wi\u0119cej o obs\u0142udze <code>this<\/code>na pocz\u0105tku <a href=\"https:\/\/reactjs.org\/docs\/faq-functions.html\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">strony FAQ Reacta<\/a>.<\/p>\n<p>Pami\u0119taj te\u017c, \u017ce poniewa\u017c jeste\u015bmy teraz w klasie, musisz wywo\u0142a\u0107 wszystkie jej funkcje za pomoc\u0105 z <code>this.<\/code>przodu.<\/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>Zwr\u00f3\u0107 uwag\u0119, \u017ce pomin\u0105\u0142em rzeczywist\u0105 zawarto\u015b\u0107 <code>InspectorControls<\/code>i <code>BlockControls<\/code>aby kod by\u0142 kr\u00f3tszy. Nic w ich kodzie nie musi si\u0119 zmienia\u0107.<\/p>\n<p>Korzystamy r\u00f3wnie\u017c z faktu, \u017ce <code>return<\/code>instrukcja mo\u017ce r\u00f3wnie\u017c zwr\u00f3ci\u0107 tablic\u0119. Wszystko w tablicy b\u0119dzie renderowane jak zwykle w kolejno\u015bci, w jakiej si\u0119 znajduje. U\u0142atwia nam to wywo\u0142ywanie funkcji bezpo\u015brednio w <code>return<\/code>instrukcji.<\/p>\n<p>Oczywi\u015bcie mo\u017cna r\u00f3wnie\u017c zdefiniowa\u0107 metody cyklu \u017cycia, takie jak <code>componentDidMount()<\/code>. Nie ma r\u00f3\u017cnicy w robieniu tego w komponentach Gutenberga ni\u017c w React.<\/p>\n<h2>Konstruktor i u\u017cywanie stanu<\/h2>\n<p>Spr\u00f3bujmy zaimplementowa\u0107 stan w naszym komponencie. Nale\u017cy pami\u0119ta\u0107, \u017ce stan jest tylko czym\u015b przechowywanym tymczasowo w naszym komponencie klasy i nie jest nigdzie zapisywany \u2013 na przyk\u0142ad w atrybutach. Chodzi tylko o to, by mie\u0107 kontrol\u0119 nad \u2013 no c\u00f3\u017c \u2013 stanem Twojego komponentu. Typowe zastosowania stanu to u\u017cywanie stanu jako flagi stanu podczas oczekiwania na powr\u00f3t wywo\u0142ania asynchronicznego, przechowywanie wyniku czego\u015b tymczasowego przed zapisaniem go w atrybucie lub implementowanie blokowych \u201etryb\u00f3w podgl\u0105du\/edycji&#8221;.<\/p>\n<p>Odwo\u0142ujesz si\u0119 do stanu i stanu aktualizacji, tak jak w React; z <code>this.state<\/code>i <code>setState()<\/code>. Normalnie zainicjowa\u0142by\u015b stan w konstruktorze. A je\u015bli chodzi o definiowanie konstruktora \u2013 jest dok\u0142adnie tak, jak w React \u2013 nie zapomnij przej\u015b\u0107 <code>props<\/code>i to <code>super(props)<\/code>te\u017c zrobi\u0107. W skr\u00f3cie:<\/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>Prze\u0142\u0105cznik edycji\/podgl\u0105du w trybie blokowania<\/h3>\n<p>Wykorzystajmy to, czego nauczyli\u015bmy si\u0119 w poprzednim kroku w paskach narz\u0119dzi, aby stworzy\u0107 \u201eprze\u0142\u0105cznik tryb\u00f3w&#8221; dla naszego bloku. Wdra\u017camy pasek narz\u0119dzi z przyciskiem, kt\u00f3ry prze\u0142\u0105cza stan mi\u0119dzy trybem podgl\u0105du a trybem edycji. W trybie edycji blok otrzymuje jak zwykle dwa komponenty RichText. Ale po przej\u015bciu do trybu podgl\u0105du wy\u0142\u0105czyli\u015bmy edycj\u0119 i renderowanie wyj\u015bcia bloku.<\/p>\n<p>Najpierw tworzymy konstruktor i ustawiamy stan z jedn\u0105 w\u0142a\u015bciwo\u015bci\u0105 logiczn\u0105; <code>editMode<\/code>kt\u00f3ry zaczyna si\u0119 jako <code>true<\/code>. Jest <code>super(props)<\/code>niezb\u0119dny podczas definiowania konstruktora w komponencie React opartym na klasach.<\/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>W naszej funkcji do wyprowadzania pask\u00f3w narz\u0119dzi zmieniamy niestandardowy przycisk, kt\u00f3ry utworzyli\u015bmy wcze\u015bniej (kt\u00f3ry tylko <code>console.log<\/code>co\u015b po klikni\u0119ciu). Na jego <code>onClick<\/code>podp\u00f3rce wywo\u0142ujemy <code>setState()<\/code>i negujemy bie\u017c\u0105c\u0105 <code>editMode<\/code>warto\u015b\u0107 logiczn\u0105. Aby u\u0142atwi\u0107 u\u017cytkownikowi zrozumienie, prze\u0142\u0105czamy si\u0119 r\u00f3wnie\u017c mi\u0119dzy ikon\u0105 przycisku a etykiet\u0105. Np. gdy tryb podgl\u0105du jest aktywny, przycisk pokazuje etykiet\u0119 \u201eEdytuj&#8221; i ikon\u0119 o\u0142\u00f3wka, kt\u00f3ra jest powszechnie akceptowana jako edycja.<\/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>I wreszcie w g\u0142\u00f3wnej metodzie renderowania naszego bloku mo\u017cemy zrobi\u0107, co chcemy. Ta cz\u0119\u015b\u0107 zale\u017cy od Ciebie \u2013 robisz to samo, co my zrobili\u015bmy z etykiet\u0105 i ikon\u0105 na powy\u017cszym przycisku. Dodajemy dwa bloki danych wyj\u015bciowych, jeden if <code>this.state.editMode<\/code>is <code>true<\/code>(kt\u00f3ry powinien by\u0107 zwyk\u0142ymi edytowalnymi <code>RichText<\/code>komponentami), a drugi if is <code>false<\/code>.<\/p>\n<p>Jako przyk\u0142ad u\u017cywam dw\u00f3ch komponent\u00f3w WordPress z <code>wp.components<\/code>; <code>Placeholder<\/code>oraz <code>Disabled<\/code>dla trybu podgl\u0105du. Komponent <code>Placeholder<\/code>umieszcza tw\u00f3j blok w \u0142adnym szarym polu, co czyni go naprawd\u0119 jasnym, \u017ce nie mo\u017cna go edytowa\u0107. Pami\u0119taj, \u017ce jest do\u0142\u0105czony do stylizacji, wi\u0119c je\u015bli chcesz uzyska\u0107 doskona\u0142y podgl\u0105d, mo\u017ce to nie by\u0107 dla Ciebie. A tak\u017ce <code>Disabled<\/code>owijam wszystko wewn\u0105trz komponentu, dzi\u0119ki czemu wszystko wewn\u0105trz jest nieedytowalne, niemo\u017cliwe do klikni\u0119cia i przeci\u0105gania. To jest nasza nowa <code>render()<\/code>funkcja w naszym komponencie:<\/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>U\u017cywam r\u00f3wnie\u017c komponentu <code>Fragment<\/code>( <code>wp.element<\/code>pakietu), kt\u00f3ry jest taki sam jak <code>React.Fragment<\/code>. Je\u015bli go nie znasz, zawijamy w nim dane wyj\u015bciowe, gdy nie chcemy dodawa\u0107 dodatkowych zb\u0119dnych opakowa\u0144 HTML. W React wszystko musi mie\u0107 w\u0119ze\u0142 g\u0142\u00f3wny. Gdy tryb edycji jest aktywny (line <code>#13<\/code>) wypisujemy dwa <code>RichText<\/code>komponenty zaraz po sobie, wi\u0119c potrzebujemy wok\u00f3\u0142 nich rootnoda.<\/p>\n<p>Gdy tryb podgl\u0105du jest aktywny (linia <code>#29<\/code>) wyprowadzamy warto\u015bci dw\u00f3ch <code>RichText<\/code>sk\u0142adnik\u00f3w. Podobnie jak w <code>save<\/code>, u\u017cywamy <code>RichText.Content<\/code>do zwracania ich warto\u015bci zamiast ma\u0142ego edytora.<\/p>\n<p>Komponent <code>Placeholder<\/code>jest dost\u0119pny w stylu flex i domy\u015blnie z wierszem flex-direction. Podanie <code>true<\/code>we w\u0142a\u015bciwo\u015bciach <code>isColumnLayout<\/code>zmienia j\u0105 na kolumn\u0119 flex-direction (wi\u0119c wszystko si\u0119 uk\u0142ada). Ale jak wspomniano wcze\u015bniej \u2013 mo\u017cesz pomin\u0105\u0107 ten komponent i raczej wygenerowa\u0107 podgl\u0105d dok\u0142adnie tak, jak by\u0142by w interfejsie.<\/p>\n<p>I dzi\u0119ki temu mamy prze\u0142\u0105cznik podgl\u0105du\/edycji trybu blokowego. Oczywi\u015bcie mo\u017cesz dostosowa\u0107 zawarto\u015b\u0107 \u201etrybu edycji&#8221;, aby pokaza\u0107 np. wej\u015bcia steruj\u0105ce lub inne.<\/p>\n<\/p>\n<p>Mo\u017cesz stworzy\u0107 tyle komponent\u00f3w, ile chcesz, nie ograniczasz si\u0119 tylko do posiadania jednego dla <code>edit<\/code>funkcji! Po prostu utw\u00f3rz wi\u0119cej komponent\u00f3w i uwzgl\u0119dnij je w <code>return<\/code>zestawieniu. To jest w\u0142a\u015bnie idea Reacta \u2013 budowanie zamkni\u0119tych fragment\u00f3w kodu, z kt\u00f3rych ka\u017cdy mo\u017ce obs\u0142ugiwa\u0107 sw\u00f3j w\u0142asny stan i \u0142\u0105czenie ich w z\u0142o\u017cone interfejsy u\u017cytkownika.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/awhitepixel.com\" class=\"external external_icon\">awhitepixel.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>W tej cz\u0119\u015bci naszego samouczka dotycz\u0105cego bloku Gutenberga dowiemy si\u0119, jak przenie\u015b\u0107 funkcj\u0119 edycji registerBlockType do oddzielnego komponentu opartego na klasie.<\/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":[897,721,721,940,940,897,1110,805,805,836,836,845,845,866,866],"tags":[1169],"class_list":{"0":"post-233553","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","6":"hentry","7":"category-kod","8":"category-deweloper","10":"category-gutenberg-7","13":"category-n-a","14":"category-php-7","16":"category-przewodnik-dla-poczatkujacych","18":"category-samouczki","20":"category-wordpress-7","22":"tag-affiai-pl"},"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/233553","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/comments?post=233553"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/233553\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/152941"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=233553"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=233553"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=233553"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}