
Geschrieben von Kristofer Selbekk in Zusammenarbeit mit Caroline Odden . Basierend auf einem Vortrag mit demselben Namen und denselben Personen beim ReactJS-Treffen in Oslo im Juni 2019.
Vom Übersetzer - der ursprüngliche Name von The 10 Component Commandments erwähnt React nicht, aber die meisten Beispiele und Empfehlungen beziehen sich speziell auf die Reaktion. Außerdem ist der Artikel unter dem React-Tag angeordnet und die Entwickler haben die Reaktion geschrieben .
Es ist nicht einfach, Komponenten zu erstellen, die viele Entwickler verwenden werden. Sie müssen sorgfältig überlegen, welche Requisiten verwendet werden sollen, wenn diese Requisiten Teil der öffentlichen API sind.
In diesem Artikel werden wir eine kurze Einführung in einige der Best Practices für die Entwicklung der API als Ganzes geben und zehn Gebote formulieren, mit denen Sie Komponenten erstellen können, die Ihre Mitentwickler gerne verwenden.

Was ist eine API?
In einer API - oder Anwendungsprogrammierschnittstelle - treffen sich zwei Codeteile. Dies ist die Kontaktfläche zwischen Ihrem Code und dem Rest der Welt. Wir nennen diese Oberfläche eine Schnittstelle. Dies ist ein bestimmter Satz von Aktionen oder Datenpunkten, mit denen Sie interagieren können.
Die Schnittstelle zwischen der Klasse und dem Code, der diese Klasse aufruft, ist ebenfalls eine API. Sie können die Methoden der Klasse aufrufen, um Daten zu empfangen, oder die darin enthaltenen Funktionen ausführen.
Nach dem gleichen Prinzip, den Requisiten, die Ihre Komponente akzeptiert, ist dies ihre API . Auf diese Weise interagieren Entwickler mit Ihrer Komponente.
Einige Best API Design Practices
Welche Regeln und Überlegungen gelten also bei der Entwicklung einer API? Nun, wir haben ein wenig recherchiert und es stellte sich heraus, dass es zu diesem Thema viele großartige Ressourcen gibt. Wir haben zwei ausgewählt - Josh Tauberer - "Was macht eine gute API aus?" und ein Artikel von Ron Kurir mit dem gleichen Titel - und kam zu diesen vier Praktiken.
Stabile Versionen
Eines der wichtigsten Dinge, die beim Erstellen einer API berücksichtigt werden müssen, ist, sie so stabil wie möglich zu halten. Die Anzahl der kritischen Änderungen sollte minimal sein. Wenn Sie wichtige Änderungen vornehmen müssen, schreiben Sie unbedingt detaillierte Update-Anleitungen und, wenn möglich, einen Mod-Code, der diesen Prozess für Entwickler automatisiert.
Beschreibende Fehlermeldungen
Wenn beim Aufrufen Ihrer API ein Fehler auftritt, sollten Sie alles tun, um zu erklären, was schief gelaufen ist und wie Sie ihn beheben können. Wenn Sie den Benutzer mit Nachrichten wie "Missbrauch" beschimpfen und keine Erklärung abgeben, hinterlässt Ihre API einen schlechten Eindruck.
Schreiben Sie stattdessen beschreibende Fehler, die dem Benutzer helfen, die Verwendung Ihrer API zu korrigieren.
Minimieren Sie Überraschungen für Entwickler
Entwickler sind fragile Kreaturen, und Sie sollten sie nicht erschrecken, wenn sie Ihre API verwenden. Mit anderen Worten, machen Sie Ihre API so intuitiv wie möglich. Sie erreichen dies, wenn Sie Best Practices und bestehende Namenskonventionen befolgen.
Außerdem sollte Ihr Code immer konsistent sein. Wenn Sie die logischen Namen von Eigenschaften mit is
oder has
an einer Stelle verwenden, diese aber weiter überspringen, werden die Benutzer verwirrt.
API-Oberfläche minimieren
Ihre API muss ebenfalls minimiert werden. Viele Funktionen sind großartig, aber je kleiner die Oberfläche Ihrer API (API-Oberfläche) ist, desto weniger Entwickler müssen sie untersuchen, um produktiv damit arbeiten zu können. Dank dessen wird Ihre API als benutzerfreundlich empfunden!
Es gibt immer eine Möglichkeit, die Größe Ihrer APIs zu steuern. Eine davon ist die Umgestaltung der neuen API von der alten.
Die zehn Gebote für Webkomponenten

Diese vier goldenen Regeln funktionieren also gut für die REST-API und für die alten prozeduralen Teile von Pascal - aber wie können sie in die moderne Welt von React übertragen werden?
Wie bereits erwähnt, haben Komponenten eine eigene API. Wir nennen sie props
, und mit ihrer Hilfe werden die Daten an die Komponenten übertragen. Wie strukturieren wir Requisiten, um keine der oben genannten Regeln zu verletzen?
Wir haben diese Liste mit zehn goldenen Regeln erstellt , die beim Erstellen Ihrer Komponenten am besten befolgt werden. Wir hoffen, dass sie Ihnen nützlich sein werden.
1. Dokumentieren Sie die Verwendung von Komponenten
Wenn die Art und Weise, wie Sie Ihre Komponente verwenden möchten, nicht dokumentiert ist, ist diese Komponente unbrauchbar. Nun, fast nutzlos, Sie können sich immer die Implementierung ansehen, aber nur wenige Leute tun dies gerne.
Es gibt viele Möglichkeiten, Ihre Komponenten zu dokumentieren. Wir empfehlen jedoch, diese drei Punkte zu beachten:
Die ersten beiden geben Ihnen einen Arbeitsplatz bei der Entwicklung Ihrer Komponenten, und die dritte ermöglicht es Ihnen, Dokumentation in freier Form mit MDX zu schreiben
Egal, für was Sie sich entscheiden, dokumentieren Sie immer sowohl die API selbst als auch wie und wann Ihre Komponenten verwendet werden sollen . Der letzte Teil ist in Allzweckbibliotheken von entscheidender Bedeutung - damit Benutzer eine Schaltfläche oder ein Layoutraster in einem bestimmten Kontext korrekt verwenden können.
2. Aktivieren Sie die kontextbezogene Semantik
HTML ist eine Sprache zur semantischen Strukturierung von Informationen. Nur hier bestehen die meisten unserer Komponenten aus <div />
-Tags. Dies ist sinnvoll - universelle Komponenten können nicht im Voraus wissen, wie sie aussehen werden, z. B. <article />
oder <section />
oder <aside />
-, aber diese Situation ist alles andere als ideal.
Es gibt noch eine andere Option: Lassen Sie Ihre Komponenten prop as
akzeptieren und bestimmen Sie dabei, welches DOM-Element gerendert wird. Hier ist ein Beispiel für die Implementierung:
function Grid({ as: Element, ...props }) { return <Element className="grid" {...props} /> } Grid.defaultProps = { as: 'div', };
Wir benennen prop in Bezug auf die Element
und verwenden es in unserer JSX. Wir geben einen gemeinsamen Standard- div
Wert an, wenn wir kein semantischeres HTML-Tag übergeben müssen.
Wenn die Zeit gekommen ist, die <Grid />
-Komponente zu verwenden, können Sie einfach das richtige Tag übergeben:
function App() { return ( <Grid as="main"> <MoreContent /> </Grid> ); }
Dies funktioniert auch mit React-Komponenten. Wenn Sie beispielsweise möchten, dass die Komponente <Button />
den React Router <Link />
:
<Button as={Link} to="/profile"> Go to Profile </Button>
3. Vermeiden Sie boolesche Requisiten
Logische Requisiten sind eine gute Idee. Sie können ohne Wert verwendet werden, daher sieht es sehr elegant aus:
<Button large>BUY NOW!</Button>
Obwohl es gut aussieht, lassen logische Eigenschaften nur zwei Möglichkeiten zu. Ein oder Aus Sichtbar oder versteckt. 1 oder 0.
Wann immer Sie anfangen, logische Eigenschaften für Dinge wie Größe, Optionen, Farben oder irgendetwas anderes einzuführen, das etwas anderes als eine binäre Auswahl sein kann, haben Sie Probleme.
<Button large small primary disabled secondary> ?? </Button>
Mit anderen Worten, logische Eigenschaften lassen sich häufig nicht mit sich ändernden Anforderungen skalieren. Stattdessen ist es für Werte, die möglicherweise etwas anderes als eine binäre Auswahl sind, besser, aufgezählte Werte wie Zeichenfolgen zu verwenden.
<Button variant="primary" size="large"> </Button>
Dies bedeutet nicht, dass logische Eigenschaften überhaupt nicht verwendet werden können. Sie können! Die oben aufgeführte disabled
Requisite sollte immer noch logisch sein - da zwischen Ein und Aus kein mittlerer Zustand besteht. Lassen Sie einfach die booleschen Eigenschaften nur für eine wirklich binäre Auswahl.
4. Verwenden Sie props.children
React hat einige spezielle Eigenschaften, die anders behandelt werden als andere. Einer dieser key
wird benötigt, um die Reihenfolge der Listenelemente zu verfolgen. Und eine andere solche besondere Requisite sind children
.
Alles, was Sie zwischen das öffnende und das schließende Tag der Komponente setzen, befindet sich in der props.children
. Und Sie sollten dies so oft wie möglich verwenden.
Warum? Weil es viel einfacher ist, Requisiteninhalte für Inhalte oder ähnliches zu haben, die normalerweise nur einfache Werte wie Text annehmen.
<TableCell content="Some text" /> // <TableCell>Some text</TableCell>
Die Verwendung von props.children
bietet mehrere Vorteile. Erstens ähnelt dies der Funktionsweise von normalem HTML. Zweitens können Sie frei übertragen, was Sie wollen! Anstatt Ihrer Komponente Requisiten wie leftIcon
und rightIcon
, übergeben Sie sie einfach als Teil der props.children
:
<TableCell> <ImportantIcon /> Some text </TableCell>
Sie können argumentieren, dass Ihre Komponente nur einfachen Text rendern muss, und in einigen Fällen ist dies der Fall. Bis irgendwann. Mit props.children
garantieren Sie, dass Ihre API für sich ändernde Anforderungen bereit ist.
5. Lassen Sie den Elternteil an der internen Logik festhalten
Manchmal erstellen wir Komponenten mit viel interner Logik und Zuständen - zum Beispiel Autocomplete oder interaktive Diagramme.
Solche Komponenten leiden häufig unter übermäßigen APIs. Einer der Gründe dafür ist die große Anzahl unterschiedlicher Anwendungsfälle, die sich bei der Entwicklung des Projekts ansammeln.
Aber was wäre, wenn wir nur eine einzige standardisierte Requisite bereitstellen könnten, mit der der Entwickler das Standardverhalten der Komponente steuern, darauf reagieren oder einfach ändern kann?
Kent Dodds schrieb einen ausgezeichneten Artikel über das Konzept der staatlichen Reduzierungen. Hier ist ein Artikel über das Konzept selbst und hier ist ein Artikel darüber, wie dies für React-Hooks implementiert wird .
Kurz gesagt, dies ist ein Funktionsübertragungsmuster für die Statusreduzierung auf Ihre Komponente, mit dem der Entwickler auf alle in Ihrer Komponente ausgeführten Aktionen zugreifen kann. Sie können den Zustand ändern oder sogar Nebenwirkungen verursachen. Dies ist eine großartige Möglichkeit, ein hohes Maß an Anpassung ohne Requisiten bereitzustellen.
So könnte es aussehen:
function MyCustomDropdown(props) { const stateReducer = (state, action) => { if (action.type === Dropdown.actions.CLOSE) { buttonRef.current.focus(); } }; return ( <> <Dropdown stateReducer={stateReducer} {...props} /> <Button ref={buttonRef}>Open</Button> </> }
Übrigens können Sie einfachere Möglichkeiten erstellen, um auf Ereignisse zu reagieren. Die Verwendung der onClose
im vorherigen Beispiel erleichtert wahrscheinlich die Verwendung der Komponente. Verwenden Sie bei Bedarf das Muster "Zustandsreduzierer".
6. Verwenden Sie den Spread-Operator für die restlichen Requisiten
Stellen Sie bei jedem Erstellen einer neuen Komponente sicher, dass Sie die Auslassungspunkte auf die verbleibenden Requisiten anwenden und sie an das Element senden, für das dies sinnvoll ist.
Sie müssen Ihrer Komponente keine Requisiten mehr hinzufügen, die einfach an die Basiskomponente oder das Basiselement übergeben werden. Dadurch wird Ihre API stabiler, da viele kleine Versionsfehler nicht mehr erforderlich sind, wenn der nächste Entwickler einen neuen Ereignis-Listener oder ein neues ARIA-Tag benötigt.
Sie können es so machen:
function ToolTip({ isVisible, ...rest }) { return isVisible ? <span role="tooltip" {...rest} /> : null; }
onClick
sicher, dass ein anderer Entwickler dasselbe tun kann, wenn Ihre Komponente Requisiten an Ihre Implementierung übergibt, z. B. einen Klassennamen oder einen onClick
Handler. Im Fall einer Klasse können Sie die Requisitenklasse einfach mithilfe der praktischen npm-Klassennamenbibliothek (oder nur der Verkettung von Zeichenfolgen) hinzufügen:
import classNames from 'classnames'; function ToolTip(props) { return ( <span {...props} className={classNames('tooltip', props.tooltip)} /> }
Bei Klick-Handlern und anderen Rückrufen können Sie diese mit einem kleinen Dienstprogramm zu einer Funktion kombinieren. Hier ist eine Möglichkeit, dies zu tun:
function combine(...functions) { return (...args) => functions .filter(func => typeof func === 'function') .forEach(func => func(...args)); }
Hier erstellen wir eine Funktion, die eine Liste von Funktionen zum Kombinieren akzeptiert. Es wird ein neuer Rückruf zurückgegeben, der alle nacheinander mit denselben Argumenten aufruft.
Diese Funktion kann folgendermaßen verwendet werden:
function ToolTip(props) { const [isVisible, setVisible] = React.useState(false); return ( <span {...props} className={classNames('tooltip', props.className)} onMouseIn={combine(() => setVisible(true), props.onMouseIn)} onMouseOut={combine(() => setVisible(false), props.onMouseOut)} /> ); }
7. Verwenden Sie die Standardwerte
Stellen Sie sicher, dass Sie Ihren Requisiten genügend Standardeinstellungen (Standardeinstellungen) geben. Auf diese Weise reduzieren Sie die Anzahl der obligatorischen Requisiten. Dies vereinfacht Ihre API erheblich.
Nehmen Sie zum Beispiel den onClick
Handler. Wenn Ihr Code diesen Handler nicht benötigt, verwenden Sie die leere Funktion (Noop-Funktion) als Standard-Requisite. Auf diese Weise können Sie es in Ihrem Code so aufrufen, als ob es immer übergeben wurde.
Ein anderes Beispiel könnte für Benutzereingaben sein. Angenommen, die Eingabezeichenfolge ist eine leere Zeichenfolge, sofern nicht anders angegeben. Auf diese Weise können Sie sicherstellen, dass Sie immer mit einem Zeichenfolgenobjekt arbeiten, nicht mit etwas Undefiniertem oder Nullem.
8. HTML-Attribute müssen nicht umbenannt werden
HTML als Sprache hat seine eigenen Requisiten oder Attribute und ist selbst eine API für HTML-Elemente. Warum also nicht diese API weiter verwenden?
Wie bereits erwähnt, sind die Minimierung der API-Oberfläche und ihre Intuitivität nützliche Methoden zur Verbesserung der API Ihrer Komponenten. Verwenden Sie also nicht einfach ein vorhandenes aria-label
anstatt Ihre eigene screenReaderLabel
Requisite zu erstellen.
Vermeiden Sie es, vorhandene HTML-Attribute für Ihre eigene "Benutzerfreundlichkeit" umzubenennen. Sie ersetzen nicht einmal die vorhandene API - Sie fügen einfach Ihre eigene hinzu. Die Leute können das aria-label
zusammen mit Ihrer screenReaderLabel- screenReaderLabel
- und was sollte dann der endgültige Wert sein?
Stellen Sie außerdem sicher, dass Sie HTML-Attribute in Ihren Komponenten niemals überschreiben. Ein gutes Beispiel ist das type
Attribut des <button />
-Elements. Es kann submit
(Standard), button
oder reset
. Viele Entwickler definieren diese Requisite jedoch neu, um den visuellen Typ der Schaltfläche ( primary
, cta
usw.) zu cta
.
Wenn Sie eine solche Requisite verwenden, müssen Sie eine Überschreibung für das Attribut true type
hinzufügen. Dies führt zu Verwirrung, Zweifel und Ärger seitens der Entwickler.
Glauben Sie mir - ich habe diesen Fehler immer wieder gemacht - wenn Sie ihn machen, müssen Sie ihn für eine lange Zeit entwirren.
9. Schreiben Sie die Arten von Requisiten (oder nur Typen)
Keine Dokumentation ist so gut wie die Dokumentation in Ihrem Code. React bietet eine hervorragende Möglichkeit, Ihre APIs mithilfe des prop-types
Pakets zu deklarieren. Verwenden Sie es.
Sie können beliebige Formatanforderungen für Ihre obligatorischen und optionalen Requisiten festlegen und diese mit JSDoc-Kommentaren verbessern.
Wenn Sie keine obligatorischen Requisiten angeben oder keinen ungültigen oder unerwarteten Wert übergeben, erhalten Sie zur Laufzeit eine Warnung in der Konsole. Dies hilft sehr bei der Entwicklung und kann aus der Produktion entfernt werden.
Wenn Sie Ihre React-Anwendungen in TypeScript schreiben oder Flow verwenden, erhalten Sie die API-Dokumentation als Sprachfunktion. Dies verbessert die Unterstützung der Entwicklungstools weiter und vereinfacht die Arbeit.
Wenn Sie selbst kein typisiertes JavaScript verwenden, sollten Sie dennoch in Betracht ziehen, den Entwicklern, die es verwenden, Typdefinitionen bereitzustellen. Dann ist es für sie viel einfacher, Ihre Komponenten zu verwenden.
10. Design für Entwickler
Schließlich die wichtigste Regel zu befolgen. Stellen Sie sicher, dass Ihre API und die Arbeit mit Ihren Komponenten für Entwickler optimiert sind, die sie verwenden.
Eine Möglichkeit, die Arbeit eines Entwicklers zu vereinfachen, besteht darin, ihm Feedback zu unangemessener Verwendung zu geben. Tun Sie dies mit Fehlermeldungen und auch, aber nur während der Entwicklung, mit Warnungen, dass es effizientere Möglichkeiten gibt, Ihre Komponente zu verwenden.
Geben Sie beim Schreiben von Fehlern und Warnungen Links zu Ihrer Dokumentation an oder zeigen Sie einfache Codebeispiele. Je schneller der Entwickler versteht, wo das Problem liegt und wie es behoben werden kann, desto komfortabler fühlt sich Ihre Komponente für die Arbeit an.
Unglaublich, aber wie sich herausstellte, hat das Vorhandensein all dieser langen Fehlerwarnungen keinen Einfluss auf die Größe des endgültigen Pakets. Dank der Wunder, toten Code zu eliminieren, können all dieser Text und Fehlercode während der Montage in der Produktion entfernt werden.
Eine der Bibliotheken, die unglaublich gutes Feedback gibt, ist React selbst. Es spielt keine Rolle, ob Sie vergessen haben, den Schlüssel für die Listenelemente anzugeben, die Lebenszyklusmethode falsch geschrieben haben oder die Basisklasse erweitert oder den Hook auf unsichere Weise aufgerufen haben. In jedem Fall werden in der Konsole große Fehlermeldungen angezeigt. Warum sollten Entwickler, die Ihre Komponenten verwenden, weniger von Ihnen erwarten?
Entwerfen Sie also für Ihre zukünftigen Benutzer. Entwerfen Sie selbst aus der Zukunft. Entwerfen Sie für die Unglücklichen, die Ihren Code pflegen müssen, wenn Sie gehen! Design für Entwickler.
Insgesamt
Wir können viel vom klassischen API-Ansatz lernen. Befolgen Sie die Tipps, Tricks, Regeln und Gebote dieses Artikels, um Komponenten zu erstellen, die einfach zu verwenden, leicht zu warten, intuitiv und bei Bedarf sehr flexibel sind.