Skapa anpassat Gutenberg-block – Del 7: Skapa dina egna anpassade komponenter
Hittills i denna handledningsserie har vi skrivit all kod inuti registerBlockType()
funktionen edit
. Det är fullt möjligt och rekommenderas ofta att istället tilldela redigering till en separat komponent. Genom att göra det kan vi använda funktionalitet som komponenttillstånd och livscykelmetoder. Den är också mycket renare, läsbar och ger återanvändbar kod!
Om du inte är bekant med att skapa React-komponenter eller vad tillstånd och livscykelmetoder är, rekommenderar jag att du läser Reacts officiella guide om detta ämne först.
Definiera en klasskomponent föredit
Du kan definiera en komponent antingen som en funktion eller en klass. Med en klasskomponent kan du använda funktionalitet som till exempel tillstånd och livscykelmetoder. Men i nyare React-versioner (16+) kan du använda React-krokar för att simulera tillstånd och livscykelmetoder inuti funktionskomponenter. Men i den här handledningen kommer vi att fokusera på att skapa en klasskomponent. Det vi har skapat hittills i den här serien, "inline" i registerBlockType()
för edit
och save
, är funktionskomponenter.
För att definiera en klasskomponent utökar vi WordPress’ Component
(i wp.element
paketet), precis som du skulle utöka en klasskomponent till React.Component
.
Tänk på att din klasskomponent måste innehålla funktionen render()
. Och på grund av hur Javascript fungerar måste din klass definieras före ditt registerBlockType()
samtal (skriv din klasskomponent först i filen och behåll registerBlockType()
efter den. Senare i det här inlägget kommer vi att lära oss hur du separerar komponenter i separata filer, exporterar och inkluderar dem).
Kort sagt, såhär:
Rekvisitan från edit
appliceras automatiskt på vår komponent. Glöm inte att en klasskomponent du behöver hänvisa till rekvisita med this.props
. Det är vanligt i WordPress Gutenberg core att använda separata komponenter för edit
funktionerna då de oftast innehåller mycket mer kod. Funktionen save
kan ofta lämnas kvar registerBlockType()
om den inte innehåller mycket kod också.
Genom att göra detta kan du nu skriva din komponent precis som du skulle göra med React. Du kan lägga till funktioner, konstruktör, tillstånd och livscykelmetoder.
Det här är koden vi hamnade i det sista steget, omvandlad till en klasskomponent:
Om du destrukturerade attributes
och setAttributes
från rekvisita som vi gjorde, är allt du behöver ändra när du flyttar till en separat klasskomponent att ändra en rad; #9
från props
till this.props
. All kod kommer att fungera precis som tidigare utan att fixa något annat. Det är det fina med att förstöra. Om du inte destrukturerade det och hänvisade till t.ex. props.attributes
direkt, skulle du behöva lägga this.
till framför alla individuella referenser till attributes
och setAttributes
överallt.
Låt oss börja göra saker vi nu kan göra med en klasskomponent!
Definiera funktioner ochthis
Visst, ja, du kan definiera funktioner inifrån edit
funktionskomponenten innan du anropar return
. Men personligen har jag alltid föredragit att separera funktionalitet med logik. Jag tycker att det är bättre att separera funktioner för logik och andra ändamål utanför funktionen som är ansvarig för att rendera utdata. Vissa människor föredrar också att anropa funktioner i händelser, istället för att göra dem inline som vi har gjort hittills (gör setAttributes()
till onChange
exempel).
Just nu har vår kod två saker som kan vara fördelaktiga för att flytta ut till funktioner; InspectorControls
och BlockControls
. Detta kommer att förkorta vår return
avsevärt och göra vår kod lättare att läsa.
Vi definierar två funktioner som returnerar hela InspectorControls
blocket och hela BlockControls
blocket. Genom att använda pilfunktioner (functionName =() => { ... }
) har vi full tillgång till this
för att få tag på rekvisita. Om du inte gjorde den sista delen av steg 1 – att ställa in Babel med de senaste syntaxerna, kommer du att få kompileringsfel. Du måste tillgripa att skapa en konstruktor och bindning this
för varje funktion. Du kan läsa mer om hantering this
i början av Reacts FAQ-sida.
Kom också ihåg att eftersom vi är i en klass nu måste du anropa alla dess funktioner med this.
framför.
Observera att jag har uteslutit det faktiska innehållet i InspectorControls
och BlockControls
för att hålla koden kortare. Ingenting i deras kod behöver ändras.
Vi använder också det faktum att return
uttalandet också kan returnera en array. Allt i arrayen kommer att renderas som vanligt i den ordning de är i. Detta gör det enkelt för oss att anropa funktioner direkt inuti return
satsen.
Du kan självklart också definiera livscykelmetoder, som componentDidMount()
. Det är ingen skillnad på att göra dessa i Gutenberg-komponenter än i React.
Konstruktör och använder tillstånd
Låt oss försöka implementera tillstånd i vår komponent. Tänk på att tillstånd bara är något som lagras tillfälligt i vår klasskomponent och inte sparas någonstans – till exempel i attribut. Det är bara för att ha kontroll över – ja – tillståndet för din komponent. Vanliga användningar av tillstånd är att använda tillstånd som en statusflagga i väntan på att ett asynkront samtal ska återkomma, att hålla poängen för något tillfälligt innan det sparas i ett attribut, eller att implementera blocket "förhandsgransknings-/redigeringslägen".
Du refererar till tillstånd och uppdateringstillstånd precis som i React; med this.state
och setState()
. Normalt skulle du initialisera tillståndet i konstruktorn. Och när det gäller att definiera en konstruktör – det är precis som i React – glöm inte att passera props
och göra det super(props)
också. Kortfattat:
class FirstBlockEdit extends Component {
constructor(props) {
super(props);
this.state = {
example: 1
}
}
render() {
this.setState({ example: 2 });
console.log(this.state.example);
...
Växlare för redigering/förhandsvisning av blockläge
Låt oss använda det vi lärde oss i föregående steg i Verktygsfält för att skapa en "lägesväxlare" för vårt block. Vi implementerar ett verktygsfält med en knapp som växlar mellan förhandsgransknings- och redigeringsläge. I redigeringsläge får blocket de två RichText-komponenterna som vanligt. Men när vi bytte till förhandsgranskningsläge inaktiverade vi redigering och renderade blockutgången.
Först skapar vi en konstruktor och ställer in tillstånd med en boolesk egenskap; editMode
som börjar som true
. Detta super(props)
är nödvändigt när man definierar en konstruktor i en klassbaserad React-komponent.
class FirstBlockEdit extends Component {
constructor(props) {
super(props);
this.state = {
editMode: true
}
}
...
I vår funktion för att mata ut verktygsfälten ändrar vi den anpassade knappen vi skapade tidigare (vilket bara är console.log
något när man klickar på den). På dess onClick
rekvisita kallar vi setState()
och förnekar det nuvarande editMode
booleska värdet. För att göra det lättare för användaren att förstå växlar vi också mellan knappens ikon och etikett. T.ex. när förhandsgranskningsläget är aktivt visar knappen etiketten "Redigera" och en pennikon som vanligtvis accepteras som redigering.
Och slutligen inom huvudrenderingsmetoden för vårt block, kan vi göra vad vi vill. Den här delen är verkligen upp till dig – du gör samma sak som vi gjorde med etiketten och ikonen på knappen ovan. Vi lägger till två utdatablock, ett om this.state.editMode
är true
(som borde vara de vanliga redigerbara RichText
komponenterna), och ett annat om det är false
.
Som ett exempel använder jag två WordPress-komponenter från wp.components
; Placeholder
och Disabled
för förhandsgranskningsläget. Komponenten Placeholder
lägger ditt block i en snygg grå ruta som gör det riktigt tydligt att det inte går att redigera. Tänk på att den kommer med styling så om du ville ha en perfekt förhandsvisning kanske det inte är något för dig. Och jag lindar också allt inuti en Disabled
komponent som gör allt inuti oredigerbart, oklickbart och odragbart. Detta är vår nya render()
funktion i vår komponent:
Jag använder också en komponent Fragment
( wp.element
paket) som är samma som React.Fragment
. Om du inte är bekant med det lägger vi in utdata i det när vi inte vill lägga till extra onödiga HTML-omslag. I React måste allt ha en rotnod. När redigeringsläget är aktivt (line #13
) matar vi ut två RichText
komponenter direkt efter varandra, så vi behöver en rotnod runt dem.
När förhandsgranskningsläget är aktivt (rad #29
) matar vi ut de två RichText
komponenternas värden. Som vi gör i save
, använder vi RichText.Content
för att returnera deras värden istället för den lilla redigeraren.
Komponenten Placeholder
kommer i flex styling och som standard med flex-direction rad. Att tillhandahålla true
i rekvisitan isColumnLayout
ändrar den till flex-direction-kolumn (så att allt staplas). Men som nämnts tidigare – du kanske vill hoppa över den här komponenten och hellre generera din förhandsvisning precis som den skulle vara i frontend.
Och med det har vi en växlare för förhandsvisning/redigering av blockläge. Självklart kan du justera innehållet i "redigeringsläget" för att visa t.ex. kontrollingångar eller liknande.
Du kan skapa så många komponenter du vill, du är inte begränsad till att bara ha en för edit
funktionen! Skapa helt enkelt fler komponenter och inkludera dem i ett return
uttalande. Det är idén med React, faktiskt – att bygga inkapslade kodbitar, möjligen hantera sina egna tillstånd och kombinera dem för att göra komplexa användargränssnitt.