Wir präsentieren Ihnen eine Übersetzung eines Artikels von Scott Domes, der auf blog.bitsrc.io veröffentlicht wurde. Finden Sie unter kat heraus, warum Komponenten so klein wie möglich sein sollten und wie sich das Prinzip der alleinigen Verantwortung auf die Qualität der Anwendungen auswirkt.

Foto
Austin Kirk mit
UnsplashDer Vorteil des React-Komponentensystems (und ähnlicher Bibliotheken) besteht darin, dass Ihre Benutzeroberfläche in kleine Teile unterteilt ist, die einfach zu lesen und wiederverwendbar sind.
Diese Komponenten sind kompakt (100-200 Zeilen), sodass andere Entwickler sie leicht verstehen und ändern können.
Obwohl Komponenten in der Regel versuchen, kürzer zu sein, gibt es keine klare, strenge Beschränkung ihrer Länge. Reagieren macht es nichts aus, wenn Sie sich entscheiden, Ihre Anwendung in eine erschreckend große Komponente zu integrieren, die aus 3.000 Zeilen besteht.
... aber es lohnt sich nicht. Die meisten Ihrer Komponenten sind höchstwahrscheinlich bereits zu umfangreich - oder sie führen zu viele Funktionen aus.
In diesem Artikel werde ich beweisen, dass die meisten Komponenten (auch bei der üblichen Länge von 200 Zeilen) enger ausgerichtet sein sollten. Sie sollten nur eine Funktion ausführen und diese gut ausführen. Das sagt Eddie Osmani
hier großartig.
Tipp : Wenn Sie in JS arbeiten,
verwenden Sie Bit , um Komponenten als Legoteile zu organisieren, zusammenzusetzen und wiederzuverwenden. Bit ist ein äußerst effektives Werkzeug für dieses Unternehmen. Es hilft Ihnen und Ihrem Team, Zeit zu sparen und die Montage zu beschleunigen. Probieren Sie es einfach aus.
Lassen Sie uns zeigen, wie beim Erstellen von Komponenten
etwas schief gehen kann .
Unsere App
Stellen Sie sich vor, wir haben eine Standardanwendung für Blogger. Und hier ist was auf dem Hauptbildschirm:
class Main extends React.Component { render() { return ( <div> <header> // Header JSX </header> <aside id="header"> // Sidebar JSX </aside> <div id="post-container"> {this.state.posts.map(post => { return ( <div className="post"> // Post JSX </div> ); })} </div> </div> ); } }
(Dieses Beispiel sollte, wie viele nachfolgende, als Pseudocode betrachtet werden.)Es zeigt das obere Bedienfeld, die Seitenleiste und die Liste der Beiträge an. Alles ist einfach.
Da wir auch Beiträge herunterladen müssen, können wir dies tun, während die Komponente gemountet wird:
class Main extends React.Component { state = { posts: [] }; componentDidMount() { this.loadPosts(); } loadPosts() {
Wir haben auch eine Logik, nach der die Seitenleiste aufgerufen wird. Wenn der Benutzer auf die Schaltfläche im oberen Bereich klickt, wird die Seite beendet. Sie können es sowohl von oben als auch von der Seitenwand selbst schließen.
class Main extends React.Component { state = { posts: [], isSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() {
Unsere Komponente ist etwas komplizierter geworden, aber dennoch leicht zu lesen.
Es kann argumentiert werden, dass alle seine Teile einem Zweck dienen: der Anzeige der Hauptseite der Anwendung. Wir folgen also dem Prinzip der alleinigen Verantwortung.
Das Prinzip der alleinigen Verantwortung besagt, dass eine Komponente nur eine Funktion erfüllen soll. Wenn wir die Definition aus
wikipedia.org neu formulieren, stellt sich heraus, dass jede Komponente nur für einen Teil der Funktionalität [Anwendung] verantwortlich sein sollte.
Unsere Hauptkomponente erfüllt diese Anforderung. Was ist das Problem?
Hier ist eine andere Formulierung des Prinzips:
Jede [Komponente] sollte nur einen Grund für eine Änderung haben .
Diese Definition stammt aus Robert Martins
Buch Rapid Software Development. Prinzipien, Beispiele, Praxis “, und das ist von großer Bedeutung.
Indem wir uns auf
einen Grund für die Änderung unserer Komponenten konzentrieren, können wir bessere Anwendungen erstellen, die außerdem einfach zu konfigurieren sind.
Lassen Sie uns aus Gründen der Klarheit unsere Komponente komplizieren.
Komplikation
Angenommen, ein Monat nach der Implementierung der Hauptkomponente wurde dem Entwickler aus unserem Team eine neue Funktion zugewiesen. Jetzt kann der Benutzer einen Beitrag ausblenden (z. B. wenn er unangemessenen Inhalt enthält).
Das ist nicht schwer zu tun!
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [] };
Unser Kollege hat sich leicht darum gekümmert. Sie fügte nur eine neue Methode und eine neue Eigenschaft hinzu. Keiner derjenigen, die die kurze Liste der Änderungen durchgesehen hatten, hatte Einwände.
Ein paar Wochen später wird eine weitere Funktion angekündigt - eine verbesserte Seitenleiste für die mobile Version. Anstatt mit CSS herumzuspielen, beschließt der Entwickler, mehrere JSX-Komponenten zu erstellen, die nur auf Mobilgeräten ausgeführt werden.
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false };
Eine weitere kleine Änderung. Ein paar neue, gut benannte Methoden und eine neue Eigenschaft.
Und hier haben wir ein Problem.
Main
führt immer noch nur eine Funktion aus (Rendern des Hauptbildschirms), aber Sie sehen sich all diese Methoden an, mit denen wir uns jetzt befassen:
class Main extends React.Component { state = { posts: [], isSidebarOpen: false, postsToHide: [], isMobileSidebarOpen: false }; componentDidMount() { this.loadPosts(); } loadPosts() {
Unsere Komponente wird groß und sperrig, es ist schwer zu verstehen. Und mit der Erweiterung der Funktionalität wird sich die Situation nur noch verschlechtern.
Was ist schief gelaufen?
Einziger Grund
Kehren wir zur Definition des Prinzips der alleinigen Verantwortung zurück:
Jede Komponente sollte nur einen Grund für Änderungen haben .
Zuvor haben wir die Art und Weise geändert, in der Beiträge angezeigt werden, sodass wir unsere Hauptkomponente ändern mussten. Als nächstes haben wir die Art und Weise geändert, wie die Seitenleiste geöffnet wird - und erneut haben wir die Hauptkomponente geändert.
Diese Komponente hat viele unabhängige Gründe für Änderungen.
Dies bedeutet, dass zu viele Funktionen ausgeführt werden .
Mit anderen Worten, wenn Sie einen Teil Ihrer Komponente erheblich ändern können und dies nicht zu Änderungen in einem anderen Teil führt, hat Ihre Komponente zu viel Verantwortung.
Effizientere Trennung
Die Lösung ist einfach: Sie müssen die Hauptkomponente in mehrere Teile aufteilen. Wie kann man das machen?
Fangen wir von vorne an. Das Rendern des Hauptbildschirms bleibt in der Verantwortung der Hauptkomponente, wir reduzieren es jedoch nur, um die zugehörigen Komponenten anzuzeigen:
class Main extends React.Component { render() { return ( <Layout> <PostList /> </Layout> ); } }
Großartig
Wenn wir plötzlich das Layout des Hauptbildschirms ändern (z. B. zusätzliche Abschnitte hinzufügen), ändert sich auch Main. In anderen Fällen haben wir keinen Grund, ihn zu berühren. Großartig.
Fahren wir mit
Layout
:
class Layout extends React.Component { render() { return ( <SidebarDisplay> {(isSidebarOpen, toggleSidebar) => ( <div> <Header openSidebar={toggleSidebar} /> <Sidebar isOpen={isSidebarOpen} close={toggleSidebar} /> </div> )} </SidebarDisplay> ); } }
Das ist etwas komplizierter.
Layout
ist für das Rendern der Layoutkomponenten (Seiten- / Oberteil) verantwortlich. Wir werden jedoch nicht der Versuchung erliegen und dem
Layout
Verantwortung übertragen, zu bestimmen, ob die Seitenleiste geöffnet ist oder nicht.
Wir weisen diese Funktion der
SidebarDisplay
Komponente zu, die die erforderlichen Methoden oder den erforderlichen Status an die
Header
und
Sidebar
Komponenten übergibt.
(Das obige Beispiel ist ein Beispiel für das Muster " Requisiten über untergeordnete Elemente rendern" in "Reagieren". Wenn Sie nicht damit vertraut sind, machen Sie sich keine Sorgen. Das Vorhandensein einer separaten Komponente, die den offenen / geschlossenen Zustand der Seitenleiste steuert, ist hier wichtig.)Und dann kann die
Sidebar
selbst recht einfach sein, wenn sie nur für das Rendern der rechten Seitenleiste verantwortlich ist.
class Sidebar extends React.Component { isMobile() {
Auch hier widerstehen wir der Versuchung, JSX für Computer / mobile Geräte direkt in diese Komponente einzufügen, da es in diesem Fall zwei Gründe für die Änderung gibt.
Schauen wir uns eine andere Komponente an:
class PostList extends React.Component { state = { postsToHide: [] } filterPosts(posts) {
PostList
ändert sich nur, wenn wir die Art und Weise ändern, wie die Liste der Beiträge
PostList
. Scheint offensichtlich, oder? Genau das brauchen wir.
PostLoader
ändert sich nur, wenn wir die Art und Weise ändern, wie Posts geladen werden. Und schließlich ändert sich
Post
nur, wenn wir die Art und Weise ändern, wie der Post gerendert wird.
Fazit
Alle diese Komponenten sind winzig und erfüllen eine kleine Funktion. Die Gründe für die Änderungen sind leicht zu identifizieren und die Komponenten selbst werden getestet und korrigiert.
Jetzt ist unsere Anwendung viel einfacher zu ändern - ordnen Sie Komponenten neu an, fügen Sie neue hinzu und erweitern Sie vorhandene Funktionen. Sie müssen sich nur eine Komponentendatei ansehen, um festzustellen,
wofür sie
gedacht ist.
Wir wissen, dass sich unsere Komponenten im Laufe der Zeit ändern und wachsen werden. Die Anwendung dieser universellen Regel hilft Ihnen jedoch, technische Schulden zu vermeiden und die Geschwindigkeit des Teams zu erhöhen. Wie Sie Komponenten verteilen, liegt bei Ihnen. Denken Sie jedoch daran, dass
es nur einen Grund für das Ändern einer Komponente geben muss .
Vielen Dank für Ihre Aufmerksamkeit und freuen uns auf Ihre Kommentare!