Vor- und Nachteile von React
Warum lohnt es sich, React zu verwenden? Welche Vorteile bietet diese JavaScript-Bibliothek? Um die Antworten zu finden, tauchen Sie in diesen Artikel ein und entdecken Sie die wahren Vorteile der Verwendung von React.
Erfahren Sie, wie Sie die Sichtbarkeit von Komponenten in React mithilfe von bedingtem Rendering und Schutzkomponenten vereinfachen und verbessern können.
Heute möchte ich darüber sprechen, wie man die Sichtbarkeit der Komponenten in React. Doch bevor wir beginnen, gibt es eine kleine
Haftungsausschluss:
Die vorgestellte Lösung ist nicht sehr sicher im Sinne des Schutzes Ihrer Anwendung vor "Hackern" (wer auch immer das ist).
Denken Sie daran, dass Sie Ihre Endpunkte schützen und gute Praktiken bei der Anwendungsentwicklung anwenden müssen. Diese Lösung
macht Ihre Arbeit ein wenig einfacher.
Eine der gebräuchlichsten Funktionen ist die Anzeige von Komponenten nur für eine Gruppe von Benutzern, die bestimmte Rechte haben,
Rollen oder Privilegien. Die übliche Lösung ist das Hinzufügen einiger wenn
s zu Codedie Bedingungen manuell überprüfen und Elemente anzeigen oder nicht anzeigen.
Werfen wir einen Blick auf SimpleAppHeader
Komponente, die nur wenige Navigationselemente enthält.
<!-- wp:paragraph -->
<p><code>typescript jsx<br>
export const SimpleAppHeader: FC = () => {<br>
return (<br>
<header><br>
<nav><br>
<ul><br>
{<br>
currentUser.role === "ADMIN" &&<br>
<li>Nur-Admin-Komponente</li><br>
}<br>
{<br>
currentUser.role === "USER" &&<br>
<li>Nur-Benutzer-Komponente</li><br>
}<br>
{<br>
(currentUser.role === "ADMIN" || currentUser.role === "USER") &&<br>
<li>Nur-Admin und User Komponente</li><br>
}<br>
<li>Allgemeines Nutzungselement</li><br>
</ul><br>
</nav><br>
</header><br>
)<br>
}<br>
</code></p>
<!-- /wp:paragraph -->
Sieht "nicht schlecht" aus. Wahrscheinlich könnte man die Prüfungen in Funktionen kapseln, um die Komplexität zu verringern. currentUser
ist ein Objekt
Das hat Rolle
Eigenschaft, aber es könnte alles sein, was wir als Gegenstand unseres Kontrollmechanismus verwenden möchten.
Dieser Code hat einige Probleme. Wenn Projekt wächst, verwenden wir diese Konstruktionen wahrscheinlich an vielen Stellen. Wir müssen also kopieren,
irgendwie, Bedingungen. Dieser Code ist schwer zu pflegen und in Zukunft zu ändern. Vor allem, wenn sich die Zugriffsregeln während
Zeit z.B. müssen wir ändern currentUser
in etwas anderes. Es ist sehr schwer zu testen. Man muss viele Tests schreiben
nur um zu überprüfen, ob Ihr Zustand in Ordnung ist.
Es ist an der Zeit, diesen Code ein wenig zu vereinfachen. Wir könnten einige Methoden extrahieren und den Code kürzer und weniger komplex machen:
const isAdmin = (role: string): boolean => role === "ADMIN";
const isUser = (role: string): boolesch => role === "USER";
const isAdminOrUser = (role: string): boolean => isAdmin(role) || isUser(role);
export const VereinfachteAppKopfzeile: FC = () => {
return (
{
isAdmin(currentUser.role) &&
Nur Admin-Komponente
}
{
isUser(aktuellerBenutzer.Rolle) &&
Nur-Benutzer-Komponente
}
{
(isAdminOrUser(currentUser.role)) &&
Nur Admin und User Komponente
}
Element zur allgemeinen Verwendung
)
}
```
Sieht vielversprechend aus. Wir reduzieren Rauschen und sich wiederholende Zeilen. Der Code ist besser lesbar und leichter zu pflegen. Aber werfen Sie einen Blick auf
Funktion isAdminOrUser
. Wir haben nur zwei Rollen. Wenn wir eine dritte Rolle einführen, müssen wir eine weitere Reihe von Funktionen erstellen
die Rollen kombiniert. Zeit für eine andere Version.
Führen Sie die Funktion hasRole
die als Ersatz für unsere isX
Funktionen.
const hasRole = (role: string, requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => role === s);
return found !== undefined;
}
export const FilteringAppHeader: FC = () => {
return (
{
hasRole(currentUser.role, ["ADMIN"]) &&
Nur Admin-Komponente
}
{
hasRole(currentUser.role, ["USER"]) &&
Nur-Benutzer-Komponente
}
{
hasRole(currentUser.role, ["ADMIN", "USER"]) &&
Nur Admin und User Komponente
}
Element zur allgemeinen Verwendung
)
}
```
Jetzt sieht es gut aus. Wir haben immer noch Bedingungen im html-Teil des Codes, aber jetzt können wir testen hasRole
Funktion und vertrauen darauf, dass sie
wird mit den richtigen Parametern verwendet. Das Hinzufügen oder Ändern von Rollen ist jetzt einfacher. Wir verwenden ein Array, das alle
Rollen, die wir brauchen, zu besetzen.
Diese Lösung ist jedoch an folgende Bedingungen gebunden currentUser
Objekt. Es wird davon ausgegangen, dass das Objekt in irgendeiner Weise global oder leicht zugänglich ist in
an jeder Stelle der Anwendung. Wir können also versuchen, dies zu kapseln. Natürlich können wir es nach hasRole
Funktion:
const hasRole = (requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => currentUser.role === s);
return found !== undefined;
}
Aber das bringt uns fast nichts.
Wache
KomponenteZeit, eine Komponente zu erstellen, die die gesamte Logik kapselt. Ich nannte sie Wache
und so möchte ich es verwenden.
export const GuardedAppHeader: FC = () => {
return (
);
}
Komponente benötigen zwei Eigenschaften. Erste Kinder
für den geschützten Inhalt verantwortlich. Zweite requiredRoles
dass
eine Reihe von Rollen handhaben, die uns Zugang gewähren.
Wir brauchen die Darstellung dieser Struktur. Das ist sehr einfach. Wir erweitern den Typ React.PropsWithChildren
Das hat Kinder
Eigenschaft. Sie können diese Eigenschaft natürlich auch manuell zu Ihrem Typ hinzufügen und die Erweiterung weglassen.
interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
}
Die Komponente selbst ist ebenfalls einfach. Wir werden wiederverwenden hasRole
Funktion hier.
export const Guard = (props: IGuardProps) => {
const hasRole = (requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => currentUser.role === s);
return found !== undefined;
}
if (hasRole(props.requiredRoles)) {
return (
{props.children}
);
} else {
return ;
}
}
"`
Und ich könnte sagen, dass wir hier aufhören sollen, aber das wäre zu einfach. Jetzt haben wir eine Komponente, und wir können sie bis zum Äußersten nutzen 😀
Der erste Schritt wird die Externalisierung der Kontrollen sein. currentUser
ist ein fest kodierter Wert. Ich würde diesen Wert gerne kapseln
in einen Dienst, der "weiß", wie man Rollen verifiziert. Technisch bedeutet das, dass wir die hasRole
Funktion zu einer anderen
Klasse.
Ich schaffe eine einfache Schnittstelle IGuardService
die nur eine Eigenschaft hat - hasRole
.
export interface IGuardService {
checkRole: (roles: string[]) => boolean;
}
Eine einfache Umsetzung könnte nun so aussehen
class SimpleGuard implementiert IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
Um sie zu verwenden, müssen wir Folgendes ändern IGuardProperties
und Anwendungsfall.
export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
guardService: IGuardService;
}
// ...
const AppHeader: FC = () => {
const guardService = new SimpleGuard();
zurück (
Nur Admin-Komponente
Nur-Benutzer-Komponente
Komponente "Administrator und Benutzer
Allgemeines Nutzungselement
);
}
```
Jetzt sieht die Komponente so aus:
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.children}
);
} else {
return ;
}
}
Viel besser. GuardService
trennen uns von der Logik, die die Rollen kontrolliert. Wir können sie ändern, ohne dass dies Konsequenzen für unsere
Komponente. Üblicherweise werden Mocks in Tests und einige "echte" Implementierungen im Produktionscode verwendet.
Die nächste Verbesserung wird der Umgang mit benutzerdefinierten Verbotene
Element. Die aktuelle Lösung zeigt ein leeres Element an. Zuerst müssen wir
ändern IGuardProps
Hinzufügen der Funktion, die für dieses Element gerendert wird.
export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Dies ist eine optionale Eigenschaft, deren Name mit einem Fragezeichen endet. Es könnte also eine Funktion sein oder undefiniert
. Wir müssen
behandeln es in Wache
Komponente.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.children}
);
} else if (props.forbidden === undefined) {
return ;
} else {
return (
{props.forbidden()}
);
}
}
// ...
export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
zurückgeben (
Nur Admin-Komponente
Nur-Benutzer-Komponente
Verboten - nur Moderatoren können dies sehen
}>
Moderator-Komponente
Admin- und Benutzerkomponente
Allgemeines Nutzungselement
);
}
```
Zeit für die letzte große Änderung. Aktuelle Version Komponente unterstützt nur Rollen als String
. Wir könnten mehrere verschiedene
Typen von Eigenschaften, die wir überprüfen möchten. Zahlen oder benutzerdefinierte Typen sind nichts Besonderes. Ich werde Unterstützung für Generika hinzufügen.
Der erste Schritt sind Änderungen in IGuardService
Schnittstelle. Die Implementierungen hängen von der Art des geprüften Wertes ab. Es könnte
alles sein, also sollte die Schnittstelle damit umgehen.
export interface IGuardService {
checkRole: (roles: ROLE[]) => boolean;
}
Jetzt nimmt es Array von ROLLE
generischer Typ. Unsere einfache Implementierung wird sich ein wenig ändern.
class SimpleGuard implements IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
Wir müssen Typ-Parameter hinzufügen, aber wir könnten eine Implementierung vorbereiten, die Folgendes unterstützt IRole
Schnittstelle.
Schnittstelle IRole {
Name: String;
}
//...
class RoleGuardService implementiert IGuardService {
checkRole(roles: IRole[]): boolean {
let found: IRole | undefined = roles.find(e => e === userWithRole.role);
return found !== undefined;
}
}
```
Der zweite Schritt ist die Weitergabe dieser Änderung an IGuardProps
.
interface IGuardProps extends React.PropsWithChildren {
requiredRoles: ROLE[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Und jeweils an Wache
Komponente.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.children}
);
} else if (props.forbidden === undefined) {
return ;
} else {
return (
{props.forbidden()}
);
}
}
Und unsere Anwendungsfälle
export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
const roleService = new RoleGuardService();
return (
<header>
<nav>
<ul>
<Guard<IRole> requiredRoles={[{Name: "ADMIN"}]} guardService={roleService}>
<li>Komponente nur für Administratoren</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>
<li>Nur-Benutzer-Komponente</li>
</Guard>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
forbidden={() => <div>Verboten - nur Moderator kann dies sehen</div>}>
<li>Moderator-Komponente</li>
</Guard>
<Guard<string> requiredRoles={["USER", "ADMIN"]} guardService={guardService}>
<li>Verwaltungs- und Benutzerkomponente</li>
</Guard>
<li>Allgemeines Nutzungselement</li>
</ul>
</nav>
</header>
);
}
In diesem Beispiel verwende ich beide Implementierungen von IGuardservice
nur zu Illustrationszwecken. In realen Anwendungsfällen müssen Sie
wahrscheinlich nur einen verwenden.
Die Wache
verschachtelt werden können. Denken Sie daran, dass der Zugriff in der Reihenfolge der meisten externen Instanzen aufgelöst wird.
export const NestAppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
<header>
<nav>
<ul>
<Guard<string> requiredRoles={["USER", "ADMIN"]} guardService={guardService}>
<Guard<string> requiredRoles={["ADMIN"]} guardService={guardService}>
<li>Komponente nur für Administratoren</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>
<li>Nur-Benutzer-Komponente</li>
</Guard>
<li>Verwaltungs- und Benutzerkomponente</li>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
forbidden={() => <div>Verboten - nur Moderator kann dies sehen</div>}>
<li>Moderator-Komponente</li>
</Guard>
</Guard>
<li>Allgemeines Nutzungselement</li>
</ul>
</nav>
</header>
);
}
Im obigen Beispiel Moderator-Komponente
konnte nie erscheinen, weil der Benutzer nur eine Rolle übernehmen kann. Erste Wache
Grenzen
Rollen zu ADMIN
und BENUTZER
also MODERATOR
wird die erste Prüfung niemals bestehen.
Wir können spezialisierte Komponenten erstellen, die einige Eigenschaften verbergen.
export const AdminGuard = (props: Omit) => {
return
{props.children}
}
//...
export const SpecializedAppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Nur Admin-Komponente
Nur-Benutzer-Komponente
Forbidden - nur der Moderator kann dies sehen
}>
Komponente Moderator
Admin- und Benutzerkomponente
Allgemeines Nutzungselement
);
}
```
In diesem Fall AdminGuard
vordefinieren ADMIN
Rolle. In den Konsequenzen müssen wir explizit die Art der ROLLE
Typ
Parameter.
In diesem Artikel zeige ich Ihnen, wie Sie Folgendes erstellen und verwenden können Wache
Bauteil in React. Wir gehen von komplexem Code aus, der schwer zu
lesen und pflegen. Wir entwickeln es in einen entwicklerfreundlicheren Zustand und führen eine benutzerdefinierte funktionale Komponente ein. Als nächstes werden wir
Erweiterung der Komponente um zusätzliche Funktionalitäten, Refaktorierung des Extraktionsdienstes und schließlich Hinzufügen von generischen Typen.
Schließlich haben wir eine Komponente, die verschachtelt werden kann und einfach zu testen und zu warten ist.