Obwohl Gutenberg mit React erstellt wurde, ist der Code, den wir zum Erstellen benutzerdefinierter Blöcke schreiben, das nicht. Er ähnelt zwar definitiv einer React-Komponente, daher denke ich, dass es nützlich ist, ein wenig damit zu spielen, um sich mit dieser Art von Ansatz vertraut zu machen. Bisher gab es in dieser Reihe viel zu *lesen*, also krempeln wir die Ärmel hoch und *machen* etwas Cooles.
Artikelserie
Lassen Sie uns eine "Über mich"-Komponente erstellen
Wir werden eine einzelne React-Komponente erstellen, die die Hintergrundfarbe einer Seite und den Einführungstext basierend auf von Ihnen eingegebenen Daten aus ein paar Feldern aktualisiert. *"Ich dachte, das sollte cool sein",* höre ich Sie alle murmeln. Ich gebe zu, ich habe es vielleicht übertrieben, aber wir werden einige Kernkonzepte von **zustandsgesteuertem JavaScript** lernen, die uns nützlich sein werden, wenn wir uns mit unserem Gutenberg-Block befassen.
Zur Referenz, das ist, was wir am Ende bekommen werden
Erste Schritte
Als Erstes werden wir CodePen starten. CodePen kann kostenlos genutzt werden, also gehen Sie dorthin und erstellen Sie einen neuen Pen.
Als Nächstes werden wir einige JavaScript-Abhängigkeiten hinzufügen. Es gibt drei Editor-Bildschirme – finden Sie den `JS`-Bildschirm und klicken Sie auf das Einstellungen-Zahnrad. Dies öffnet ein Fenster "Pen-Einstellungen", in dem Sie den Abschnitt **Externe Skripte/Pens hinzufügen** finden. Ganz unten gibt es ein Dropdown-Menü **Schnell hinzufügen**. Öffnen Sie es.

Wählen Sie im Menü **React**. Sobald dies ausgewählt ist, öffnen Sie das Menü und wählen Sie **ReactDOM**. Sie werden sehen, dass dadurch einige Textfelder vorausgefüllt wurden.
Zuletzt müssen wir unseren ES6-Code aktivieren. Wählen Sie also im Menü **JavaScript-Präprozessor** **Babel**.
Klicken Sie nun auf die große Schaltfläche **Speichern & schließen**.
Was wir dort getan haben, ist, die Haupt-React-JS-Bibliothek und die ReactDOM-Bibliothek geladen zu haben. Diese ermöglichen es uns, einzutauchen und unseren Code zu schreiben, was unser nächster Schritt ist.
Richten Sie unser CSS ein
Lassen Sie es cool aussehen. Zuerst richten wir unseren CSS-Editor ein. Als Erstes richten wir ihn so ein, dass er Sass für uns kompiliert. Genau wie beim JS-Editor klicken Sie auf das Einstellungen-Zahnrad, das wieder das Modal **Pen-Einstellungen** öffnet – diesmal mit den CSS-Einstellungen.
Oben befindet sich ein Menü **CSS-Präprozessor**. Wählen Sie dort **SCSS** aus.
Wenn das erledigt ist, gehen Sie zu **Externe Stylesheets/Pens hinzufügen** und fügen Sie die folgenden drei Links in separate Textfelder ein
https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.css
https://fonts.googleapis.com/css?family=Work+Sans:300
https://rawgit.com/hankchizljaw/boilerform/master/dist/css/boilerform.min.css
Diese drei geben uns nacheinander ein Reset, eine schicke Schriftart und einige hilfreiche Formularstile.
Nachdem nun alles eingerichtet ist, klicken Sie erneut auf die Schaltfläche "Speichern & schließen".
Fügen Sie etwas Stil hinzu
Wir sind also bereit, dieser Schritt sollte einfach sein. Fügen Sie das folgende Sass in den CSS-Editor ein
:root {
--text-color: #f3f3f3;
}
* {
box-sizing: border-box;
}
html {
height: 100%;
font-size: 16px;
}
body {
height: 100%;
position: relative;
font-size: 1rem;
line-height: 1.4;
font-family: "Work Sans", sans-serif;
font-weight: 300;
background: #f3f3f3;
color: #232323;
}
.about {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
color: var(--text-color);
transition: all 2000ms ease-in-out;
&__inner {
display: flex;
flex-direction: column;
height: 100%;
margin: 0 auto;
padding: 1.2rem;
}
&__content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex: 1 1 auto;
font-size: 3rem;
line-height: 1.2;
> * {
max-width: 30ch;
}
}
&__form {
display: flex;
flex-direction: column;
align-items: center;
padding: 2rem 0;
width: 100%;
max-width: 60rem;
margin: 0 auto;
@media(min-width: 32rem) {
flex-direction: row;
justify-content: space-between;
padding: 2rem;
}
> * {
width: 15rem;
}
> * + * {
margin: 1rem 0 0 0;
@media(min-width: 32rem) {
margin: 0;
}
}
label {
display: block;
}
}
}
// Boilerform overrides
.c-select-field {
&,
&__menu {
width: 100%;
}
}
.c-input-field {
width: 100%;
}
.c-label {
color: var(--text-color);
}
Das ist ein großer Brocken CSS, und es wird aussehen, als sei nichts wirklich passiert, aber das ist gut so – wir müssen uns für den Rest dieses Abschnitts keine Sorgen mehr um CSS machen.
Tauchen wir in React ein
Als Erstes geben wir React etwas zum Anheften. Fügen Sie dies in den HTML-Editor Ihres Pens ein
<div id="root"></div>
Das war's für HTML – Sie können Ihren JS-Editor vergrößern, damit wir uns voll und ganz darauf konzentrieren können.
Beginnen wir unseren Komponenten-Code, indem wir eine neue Instanz einer React-Komponente erstellen, indem wir den folgenden JavaScript-Code schreiben
class AboutMe extends React.Component {
}
Was dieser Code tut, ist die Erstellung einer neuen `AboutMe`-Komponente und die Erweiterung der `Component`-Klasse von React, was uns eine Menge Code und Tools kostenlos zur Verfügung stellt.
Nun, wir haben eine Klasse, und jetzt müssen wir sie konstruieren! Fügen Sie den folgenden Code innerhalb der Klammern hinzu
constructor(props) {
super(props);
let self = this;
};
Hier passiert einiges, daher werde ich jeden Punkt erklären
`constructor` ist die Methode, die aufgerufen wird, wenn Sie `new AboutMe()` schreiben, oder wenn Sie `
`super` ist, wie wir der Klasse, die wir erweitert haben, sagen, dass sie mit ihrem eigenen `constructor` konstruieren soll. Sie werden sehen, dass wir auch die `props` weitergeben, falls übergeordnete Komponenten darauf zugreifen müssen.
Schließlich ist `let self = this` eine Möglichkeit, den Geltungsbereich von `this` zu steuern. Denken Sie daran, da wir `let` verwenden, ist `self` nur innerhalb der `constructor`-Funktion verfügbar.
Nachdem wir nun den Konstruktor behandelt haben, fügen wir ihm weiteren Code hinzu. Fügen Sie nach der Zeile `let self = this;` den folgenden Code ein
self.availableColors = [
{
"name": "Red",
"value": "#ca3814"
},
{
"name": "Blue",
"value": "#0086cc"
},
{
"name": "Green",
"value": "#3aa22b"
}
];
Was wir dort haben, ist ein Array von Objekten, die unsere Optionen für die Auswahl Ihrer Lieblingsfarbe definieren. Fügen Sie Ihre eigene hinzu, wenn sie noch nicht vorhanden ist!
Ihre Klassendefinition und Ihr Konstruktor sollten jetzt so aussehen
class AboutMe extends React.Component {
constructor(props) {
super(props);
let self = this;
// Set a list of available colors that render in the select menu
self.availableColors = [
{
"name": "Red",
"value": "#ca3814"
},
{
"name": "Blue",
"value": "#0086cc"
},
{
"name": "Green",
"value": "#3aa22b"
}
];
};
}
Bis hierhin ziemlich einfach, oder? Lassen Sie uns weitermachen und einige Anfangswerte für unseren reaktiven Zustand festlegen. Fügen Sie Folgendes nach dem Schließen von `self.availableColors` hinzu
// Set our initial reactive state values
self.state = {
name: 'Foo',
color: self.availableColors[0].value
};
Diese anfängliche Zustandsfestlegung ermöglicht es unserer Komponente, beim Laden sowohl einen Namen als auch eine Farbe zu rendern, was verhindert, dass sie defekt aussieht.
Als Nächstes fügen wir unsere `render`-Funktion hinzu. Dies ist eine reine Funktion, die nichts weiter tut, als die Komponente basierend auf dem anfänglichen Zustand oder Zustandsänderungen während des Lebenszyklus der Komponente zu rendern. Sie haben es vielleicht schon erraten, aber hier befindet sich der Hauptteil unseres JSX.
Da wir jetzt recht viel Markup in dieser einzelnen Komponente haben, werden wir das Ganze in unsere Funktion kopieren. Fügen Sie Folgendes unter Ihrem `constructor` hinzu
render() {
let self = this;
return (
<main className="about" style={ { background: self.state.color } }>
<section className="about__inner">
<article className="about__content">
{ self.state.name ? <p>Hello there. My name is { self.state.name }, and my favourite color is { self.getActiveColorName() }</p> : null }
</article>
<form className="[ about__form ] [ boilerform ]">
<div>
<label className="c-label" htmlFor="name_field">Your name</label>
<input className="c-input-field" type="text" id="name_field" value={ self.state.name } onChange={ self.updateName.bind(self) } />
</div>
<div>
<label className="c-label" htmlFor="color_field">Your favourite color</label>
<div className="c-select-field">
<select className="c-select-field__menu" value={ self.state.color } onChange={ self.updateColor.bind(self) } id="color_field">
{ self.availableColors.map((color, index) => {
return (
<option key={ index } value={ color.value }>{ color.name }</option>
);
})}
</select>
<span className="c-select-field__decor" aria-hidden="true" role="presentation">▾</span>
</div>
</div>
</form>
</section>
</main>
);
};
Sie denken vielleicht: "Heilige Kuh, hier passiert ja eine Menge." Lassen Sie es uns sezieren, also machen Sie sich keine Sorgen ums Kopieren von Code – ich werde Sie informieren, wann wir das wieder tun. Konzentrieren wir uns vorerst nur auf einige Schlüsselbereiche.
In JSX müssen Sie ein einzelnes Element zurückgeben, das Kindelemente enthalten kann. Da unser gesamter Code in einem `<main>`-Tag gekapselt ist, sind wir dort gut aufgestellt. Bei diesem `<main>`-Tag sehen Sie, dass wir einen Ausdruck in einem Attribut haben, wie wir ihn in Teil 2 behandelt haben. Dieser Ausdruck setzt die Hintergrundfarbe als die aktuell in unserem Zustand gesetzte aktive Farbe. Diese wird sich wie von Zauberhand aktualisieren, wenn ein Benutzer seine Farbwahl ändert, ohne dass wir dafür eine weitere Codezeile in dieser Render-Funktion schreiben müssen. Ziemlich cool, oder?
Innerhalb des `<article class="about__content">`-Elements werden Sie Folgendes bemerken
{ self.state.name ? <p>Hello there. My name is { self.state.name }, and my favourite color is { self.getActiveColorName() }</p> : null }
Dieser ternäre Operator prüft, ob ein Name gesetzt ist und rendert entweder einen Satz, der den Namen enthält, oder `null`. `null` in JSX zurückzugeben ist, wie Sie dem Client sagen, nichts zu rendern. Ebenfalls mit diesem Snippet verwandt: Wir konnten diesen ternären Operator innerhalb unseres JSX ausführen, da wir durch das Öffnen von Klammern einen Ausdruck erstellt haben. Es ist eine sehr nützliche Möglichkeit, kleine, einfache Anzeigelogiken in Ihre `render`-Funktion einzustreuen.
Als Nächstes betrachten wir eine Ereignisbindung
<input className="c-input-field" type="text" id="name_field" value={ self.state.name } onChange={ self.updateName.bind(self) } />
Wenn Sie kein Ereignis an Ihr Eingabefeld binden, ist es schreibgeschützt. Aber keine Panik, falls Sie es vergessen. React warnt Sie hilfreich in Ihrer Konsole.
Denken Sie daran, `self` ist gleich `this`, also fügen wir die Funktion `updateName` an das `onChange`-Ereignis des Eingabefeldes an, aber wir binden auch `self`, sodass, wenn wir uns innerhalb der Funktion `updateName` befinden, `this` gleich `AboutMe` ist, was unsere Komponente ist.
Das Letzte, was wir uns in der `render`-Funktion ansehen werden, sind Schleifen. Hier ist das Snippet, das das Farbauswahlmenü rendert
<select className="c-select-field__menu" value={ self.state.color } onChange={ self.updateColor.bind(self) } id="color_field">
{ self.availableColors.map((color, index) => {
return (
<option key={ index } value={ color.value }>{ color.name }</option>
);
}) }
</select>
Die Werte- und Änderungskonfiguration ist die gleiche wie beim obigen ``-Element, daher ignorieren wir sie und tauchen direkt in die Schleife ein. Wir haben einen Ausdruck geöffnet, in dem wir eine ziemlich Standard-Array-Map-Funktion ausführen, aber wichtig ist, dass sie in jeder Iteration JSX zurückgibt, was es jeder Option ermöglicht, mit dem Rest des JSX gerendert zu werden.
Alles zusammenfügen
Nachdem wir nun die Kernaspekte der Komponente am Laufen haben, müssen wir sie zusammenfügen. Sie werden feststellen, dass Ihr CodePen im Moment nichts tut. Das liegt an zwei Dingen
- Wir haben die Komponente noch nicht an das DOM angehängt
- Wir haben noch keine Methoden geschrieben, um sie interaktiv zu machen
Beginnen wir mit ersterem und fügen unsere Änderungsereignisbehandler hinzu. Fügen Sie dies unterhalb Ihres `constructor`-Funktion hinzu
updateName(evt) {
let self = this;
self.setState({
name: evt.target.value
})
};
updateColor(evt) {
let self = this;
self.setState({
color: evt.target.value
})
};
Diese beiden Funktionen behandeln die `onChange`-Ereignisse des `
Nun wäre es empfehlenswert, Ihren Code DRYer zu gestalten, indem Sie diese beiden zu einem einzigen Änderungsereignisbehandler kombinieren, der den relevanten Zustand aktualisiert. Für diese Reihe halten wir die Dinge jedoch einfach und verständlicher. 😀
Als Nächstes fügen wir die letzte Methode zu unserer Komponente hinzu. Fügen Sie dies unter Ihren kürzlich hinzugefügten Update-Methoden hinzu
// Return active color name from available colors, based on state value
getActiveColorName() {
let self = this;
return self.availableColors.filter(color => color.value === self.state.color)[0].name;
};
Diese Funktion verwendet eine meiner bevorzugten JavaScript-Array-Methoden: `filter`. Mit ES6 können wir Array-Elemente basierend auf ihrem Objektwert in einer Zeile auswählen, was mächtig ist. Mit dieser Macht können wir den menschlich lesbaren Namen des aktuell aktiven `availableColors`-Elements auswählen und zurückgeben.
Die Komponente an das DOM anhängen
Als Letztes hängen wir unsere Komponente mithilfe von ReactDOM an das DOM an. Was wir tun, ist zu sagen: "Hey Browser, hol mir das `
ReactDOM ist ein sehr intelligentes Paket, das Änderungen in Ihren dynamischen React-Komponenten aufnimmt, berechnet, was im DOM geändert werden muss, und diese Änderungen auf die effizienteste Weise anwendet. Mit der `renderToString()`-Methode von ReactDOM können Sie auch Ihre React-Komponenten in eine statische Zeichenfolge rendern, die dann mit Ihrem serverseitigen Code in Ihre Seite eingefügt werden kann. Das Geniale daran ist, dass Referenzen hinzugefügt werden, sodass, wenn Ihr Frontend einige serverseitig gerenderte React-Komponenten erkennt, es herausfindet, welche Komponenten benötigt werden und den gesamten Block statischer Markup automatisch dynamisch macht. Ziemlich genial, oder?
Aber zurück zu unserem Pen. Fügen Sie dies ganz unten in Ihren JS-Editor ein
// Attach our component to the <div id="root"> element
ReactDOM.render(<AboutMe />, document.getElementById('root'));
Nun werden Sie feststellen, dass Ihr Vorschaufenster plötzlich lebendig geworden ist! Herzlichen Glückwunsch – Sie haben gerade eine React-Komponente geschrieben 🎉
Sehen Sie den Pen About Me React Component von Andy Bell (@hankchizlja) auf CodePen.
Zusammenfassung
In diesem Teil haben Sie durch das Schreiben einer React-Komponente etwas über reaktives, komponentenbasiertes JavaScript gelernt. Dies ist für Ihr Lernen relevant, da benutzerdefinierte Gutenberg-Blöcke eine sehr ähnliche Einrichtung wie eine React-Komponente haben. Da Sie nun ein besseres Verständnis dafür haben, wie eine React-Komponente funktioniert, sollten Sie auch verstehen können, wie ein benutzerdefinierter Gutenberg-Block funktioniert.
Als Nächstes in dieser Reihe werden wir unser WordPress-Theme bearbeiten, damit wir unseren benutzerdefinierten Gutenberg-Block erstellen können.
Darf ich hier sagen, dass diese ganze Gutenberg-Reihe einfach nur erstaunlich ist? Ich habe nicht zu allen Artikeln kommentiert, weil es billig aussehen würde – aber jeden Tag habe ich etwas Neues, auf das ich mich freuen kann :)
Danke Max! Ich hoffe, Sie fanden die Serie nützlich :)
Mein CodePen funktionierte nicht. Als ich in die Konsole schaute, entdeckte ich, dass ich zuerst react-dom.development.js und dann react.development.js geladen hatte. Sobald ich die externe Ressource react.development.js nach oben verschoben habe, funktionierte alles einwandfrei.
Außerdem habe ich entdeckt, dass Sie, um Kommentare innerhalb der Render()-Funktion zu schreiben, diese in geschweifte Klammern einschließen müssen.D
Zum Beispiel: {/* Erstellen Sie eine Listbox mithilfe der JavaScript-Array-map()-Funktion */}
Ja, innerhalb Ihres JSX müssen sie in einem `{}`-Paar sein, da sie einen Ausdruck erzeugen. Aber eine gute Tipps für andere, die stecken bleiben könnten, also danke :)