Bedeuten Funktionskomponenten Funktionale Programmierung?
Emily Parker
Product Engineer · Leapcell

Langjährige React-Nutzer sind wahrscheinlich mit der Tatsache vertraut, dass React zwei Arten von Komponenten hat:
- Class Components (Klassenkomponenten)
- Function Components (Funktionskomponenten)
Angesichts der Erwähnung von "Klasse" und "Funktion" liegt es nahe, sich zu fragen:
- Stehen Klassenkomponenten in Beziehung zu OOP (Objektorientierter Programmierung)?
- Stehen Funktionskomponenten in Beziehung zu FP (Funktionale Programmierung)?
Schließlich könnten OOP-Prinzipien (Vererbung, Kapselung, Polymorphismus usw.) die Entwicklung von klassenbasierten Komponenten leiten, wenn Klassenkomponenten mit OOP assoziiert sind. In ähnlicher Weise könnten FP-Prinzipien Funktionskomponenten beeinflussen. Mit anderen Worten, wir könnten die Best Practices dieser Programmierparadigmen direkt auf React-Projekte anwenden.
Was ist also die Beziehung zwischen Funktionskomponenten und funktionaler Programmierung? Dieser Artikel untersucht dieses Thema eingehend.
Programmierparadigmen und DSL
Zunächst sollten wir klarstellen, dass die Framework-Syntax im Wesentlichen eine Art DSL (Domain-Specific Language) ist, die für die Entwicklung in einem bestimmten Bereich zugeschnitten ist.
Zum Beispiel ist React eine DSL zum Erstellen von Ansichten. Obwohl verschiedene Plattformen unterschiedliche Frameworks für Ansichten verwenden, wie zum Beispiel:
- Für Web: ReactDOM
- Für Mini-Programme: Taro
- Für native Entwicklung: ByteDances internes Framework React Lynx
Diese Frameworks folgen im Allgemeinen der gleichen DSL (React-Syntax). Diese DSL ist nicht an ein bestimmtes Programmierparadigma gebunden, sondern sollte stattdessen als eine Sammlung von Sprachmerkmalen betrachtet werden, die sich gut für die Ansichtsentwicklung eignen.
Daher kann Folgendes als Teil der React-DSL gelten:
- Funktionskomponenten können OOP-Prinzipien verkörpern.
- Klassenkomponenten können FP-Prinzipien widerspiegeln.
Solange diese Prinzipien der Ansichtsentwicklung zugute kommen, können sie in die DSL integriert werden.
Betrachten Sie zum Beispiel die folgende Funktionskomponente Header
, die aus WelcomeMessage
und LogoutButton
besteht. Dies demonstriert das OOP-Prinzip der Komposition über Vererbung:
function Header(props) { return ( <div> <WelcomeMessage name={props.name} /> <LogoutButton onClick={props.onLogout} /> </div> ); }
Betrachten Sie in ähnlicher Weise die Klassenkomponente Cpn
, bei der der Zustand count
nicht durch Mutation (this.state.count++
), sondern durch Aufrufen von this.setState
mit unveränderlichen Daten aktualisiert wird:
class Cpn extends React.Component { // ... onClick() { const count = this.state.count; this.setState({ count: count + 1 }); } render() { // ... } }
Die Verwendung unveränderlicher Daten spiegelt Prinzipien aus FP wider.
Wenn wir also eine React-Funktion untersuchen, sollten wir diese drei Schritte durchdenken:
- Was ist die grundlegende Entwicklungsphilosophie von React?
- Welche Ideen aus verschiedenen Programmierparadigmen werden verwendet, um diese Philosophie umzusetzen?
- Wie werden diese Ideen in React angewendet?
Wenden wir diesen Denkprozess auf die Beziehung zwischen Funktionskomponenten und funktionaler Programmierung an, so stellen wir fest, dass:
- Funktionskomponenten das Ergebnis der Implementierung sind (Schritt 3).
- Funktionale Programmierung ein Programmierparadigma ist (Schritt 2).
Dies definiert ihre Beziehung: Funktionskomponenten sind das Produkt der Implementierung verschiedener Programmierparadigmen (hauptsächlich OOP und FP) in React, wobei einige Ideen aus FP entlehnt wurden.
Funktionskomponenten sollten nicht nur als die Verkörperung funktionaler Programmierung in React angesehen werden.
Die Evolution von Funktionskomponenten
Lassen Sie uns die Evolution von Funktionskomponenten anhand des bereits erwähnten dreistufigen Denkprozesses untersuchen. Die Entwicklungsphilosophie von React lässt sich am besten durch diese Formel ausdrücken:
UI = fn(snapshot);
Um diese Philosophie umzusetzen, sind zwei Schlüsselelemente erforderlich:
- Datenschnappschüsse
- Funktionsmapping
Hier eignen sich unveränderliche Daten aus FP besser als Träger für Datenschnappschüsse. Aus diesem Grund ist der Zustand in React unveränderlich – das Wesen des Zustands ist ein Schnappschuss.
Der Träger für das Funktionsmapping hat keine besonderen Anforderungen. In React löst jede Aktualisierung ein erneutes Rendern aus, und der Renderprozess selbst ist der Funktionsmapping-Prozess. Die Eingabe sind props
und state
, und die Ausgabe ist JSX.
Im Gegensatz dazu orientieren sich Vue-Komponenten stärker an OOP-Prinzipien. Betrachten Sie diese Vue App
-Komponente:
const App = { setup(initialProps) { const count = reactive({count: 0}) const add = () => { count.value++ } return {count, add} } template: "...omitted" }
Die setup
-Methode der Komponente wird nur einmal während der Initialisierung ausgeführt. Nachfolgende Aktualisierungen manipulieren dieselben Daten innerhalb einer Closure, was dem Konzept einer Instanz in OOP entspricht.
Da React keine besonderen Anforderungen an den Träger für das Funktionsmapping stellt, sind sowohl Klassenkomponenten als auch Funktionskomponenten brauchbare Optionen.
Warum haben Funktionskomponenten Klassenkomponenten ersetzt?
Viele glauben, dass die verbesserte Wiederverwendbarkeit von Logik durch Hooks der Hauptgrund dafür ist, dass Funktionskomponenten Klassenkomponenten übertreffen. Das dekoratorbasierte Klassenentwicklungsmodell hat sich jedoch, insbesondere in Verbindung mit TypeScript, als effektiver Ansatz zur Logikwiederverwendung erwiesen.
Der eigentliche Grund liegt in der Fähigkeit von Funktionskomponenten, die Philosophie UI = fn(snapshot) besser umzusetzen.
Wie bereits erwähnt, stellt der snapshot
in der Formel einen Schnappschuss des Zustands dar, der in React Folgendes umfasst:
state
props
context
Für eine bestimmte Komponente stellt die Formel UI = fn(snapshot)
sicher, dass identische Schnappschüsse identische Ausgaben (JSX) erzeugen. Zustandsaktualisierungen können jedoch auch Nebenwirkungen auslösen, wie z. B. Datenabruf oder DOM-Manipulation.
In Klassenkomponenten sind diese Nebenwirkunglogiken über verschiedene Lifecycle-Methoden verstreut, was es React erschwert, sie zu kontrollieren. In Funktionskomponenten hingegen:
- Nebenwirkungen sind auf
useEffect
beschränkt. React stellt sicher, dass Effekte aus dem vorherigen Rendern bereinigt werden (über den Rückgabewert vonuseEffect
), bevor neue angewendet werden. - Die Weitergabe von
ref
ist durch Mechanismen wieforwardRef
eingeschränkt, wodurch ihre potenziellen Auswirkungen begrenzt werden. - Datenabruf-Nebenwirkungen werden von
Suspense
verwaltet, wie unten gezeigt:
function UserList({ id }) { const data = use(fetchUser(id)); // ... }
Verwendung:
<Suspense fallback={<div>Loading...</div>}> <UserList id={1} /> </Suspense>
Kurz gesagt, Funktionskomponenten stellen sicher, dass Nebenwirkungen überschaubar bleiben, wodurch konsistente Ausgaben für dieselben Schnappschusseingaben ermöglicht werden. Dies steht im Einklang mit dem FP-Konzept der reinen Funktionen, weshalb Funktionskomponenten zur Mainstream-Wahl in React geworden sind.
Fazit
Funktionskomponenten sind keine direkte Implementierung funktionaler Programmierung in React, sondern der am besten geeignete Träger zur Verwirklichung der Kernphilosophie von React: UI = fn(snapshot). React integriert hervorragende Ideen aus verschiedenen Programmierparadigmen, wobei FP das einflussreichste ist. Letztendlich dient jede Designentscheidung der übergreifenden Philosophie.
Wir sind Leapcell, Ihre erste Wahl für das Hosting von Node.js-Projekten.
Leapcell ist die Next-Gen-Serverless-Plattform für Webhosting, asynchrone Aufgaben und Redis:
Multi-Language-Unterstützung
- Entwickeln Sie mit Node.js, Python, Go oder Rust.
Stellen Sie unbegrenzt Projekte kostenlos bereit
- Zahlen Sie nur für die Nutzung – keine Anfragen, keine Gebühren.
Unschlagbare Kosteneffizienz
- Pay-as-you-go ohne Leerlaufgebühren.
- Beispiel: 25 US-Dollar unterstützen 6,94 Millionen Anfragen bei einer durchschnittlichen Reaktionszeit von 60 ms.
Optimierte Entwicklererfahrung
- Intuitive Benutzeroberfläche für mühelose Einrichtung.
- Vollständig automatisierte CI/CD-Pipelines und GitOps-Integration.
- Echtzeitmetriken und -protokollierung für verwertbare Erkenntnisse.
Mühelose Skalierbarkeit und hohe Leistung
- Automatische Skalierung zur mühelosen Bewältigung hoher Parallelität.
- Null Betriebsaufwand – konzentrieren Sie sich einfach auf den Aufbau.
Erfahren Sie mehr in der Dokumentation!
Folgen Sie uns auf X: @LeapcellHQ