Fordele og ulemper ved React
Hvorfor er det værd at bruge React? Hvilke fordele har dette JavaScript-bibliotek? For at finde svarene skal du dykke ned i denne artikel og opdage de virkelige fordele ved at bruge React.
Lær, hvordan du kan forenkle og forbedre komponenternes synlighed i React ved hjælp af betinget gengivelse og beskyttelseselementer.
I dag vil jeg gerne diskutere, hvordan man kan kontrollere komponentens synlighed i React. Men før vi begynder, er der en lille
Ansvarsfraskrivelse:
Den præsenterede løsning er ikke særlig sikker i forhold til at beskytte din applikation mod "hackere" (hvem der så end er).
Husk, at du skal beskytte dine slutpunkter og bruge god praksis i applikationsdesign. Denne løsning gør kun
gør kun dit arbejde lidt lettere.
En af de mest almindelige funktioner er kun at vise komponenter for en række brugere, der har nogle specifikke rettigheder,
roller eller rettigheder. En almindelig løsning er at tilføje nogle hvis
s til Kodemanuelt kontrollere forholdene og vise eller ikke vise elementer.
Lad os tage et kig på SimpleAppHeader
komponent, der indeholder få navigationselementer.
<!-- 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>Komponent kun til administrator</li><br>
}<br>
{<br>
currentUser.role === "USER" &&<br>
<li>Kun bruger-komponent</li><br>.
}<br>
{<br>
(currentUser.role === "ADMIN" || currentUser.role === "USER") &&<br>
<li>Kun administrator- og brugerkomponent</li><br>
}<br>
<li>Generel brug af elementet</li><br>
</ul><br>
</nav><br>
</header><br>
)<br>
}<br>
</code></p>
<!-- /wp:paragraph -->
Det ser "ikke dårligt" ud. Du kan sikkert indkapsle checks i funktioner for at reducere kompleksiteten. nuværende bruger
er et eller andet objekt
der har rolle
egenskab, men det kan være hvad som helst, som vi gerne vil bruge som genstand for vores kontrolmekanisme.
Denne kode har nogle problemer. Hvis projekt vokser, bruger vi sikkert de konstruktioner mange steder. Så vi er nødt til at kopiere,
på en eller anden måde, betingelser. Denne kode er svær at vedligeholde og ændre i fremtiden. Især når adgangsreglerne ændres i løbet af
tid f.eks. vi er nødt til at ændre nuværende bruger
til noget andet. Det er meget svært at teste. Du er nødt til at skrive mange tests
bare for at tjekke, om din tilstand er ok.
Det er tid til at forenkle koden lidt. Vi kan trække nogle metoder ud og gøre koden kortere og mindre kompleks:
const isAdmin = (role: string): boolean => role === "ADMIN";
const isUser = (role: string): boolean => role === "USER";
const isAdminOrUser = (role: string): boolean => isAdmin(role) || isUser(role);
export const SimplifiedAppHeader: FC = () => {
return (
{
isAdmin(currentUser.role) &&
Kun administrator-komponent
}
{
isUser(currentUser.role) &&
Kun bruger-komponent
}
{
(isAdminOrUser(currentUser.role)) &&
Kun administrator- og brugerkomponent
}
Element til generel brug
)
}
```
Det ser lovende ud. Vi reducerer støj og gentagne linjer. Koden er mere læsbar og lettere at vedligeholde. Men tag et kig på
funktion isAdminOrUser
. Vi har kun to roller. Hvis vi indfører en tredje rolle, skal vi oprette et andet sæt funktioner
der kombinerer roller. Tid til en ny version.
Lad os indføre funktionen harRolle
der vil være erstatning for vores isX
funktioner.
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"]) &&
Kun administrator-komponent
}
{
hasRole(currentUser.role, ["USER"]) &&
Kun bruger-komponent
}
{
hasRole(currentUser.role, ["ADMIN", "USER"]) &&.
Kun administrator- og brugerkomponent
}
Element til generel brug
)
}
```
Nu ser det godt ud. Vi har stadig betingelser i html-delen af koden, men nu kan vi teste harRolle
funktion og stole på, at den
vil blive brugt med det korrekte sæt parametre. Det er nu nemmere at tilføje eller ændre roller. Vi bruger et array, der indeholder alle
roller, som vi skal have på plads.
Denne løsning er dog bundet til nuværende bruger
objekt. Antagelsen er, at objektet på en eller anden måde er globalt eller let at få adgang til i
et hvilket som helst sted i applikationen. Så vi kan prøve at indkapsle det. Vi kan selvfølgelig flytte det til harRolle
funktion:
const hasRole = (requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => currentUser.role === s);
return found !== undefined;
}
Men det giver os næsten ingenting.
Vagt
KomponentTid til at skabe en komponent, der indkapsler hele logikken. Jeg navngav den Vagt
og det er sådan, jeg vil bruge den.
export const GuardedAppHeader: FC = () => {
return (
</header
);
}
Komponenten har brug for to egenskaber. For det første børn
ansvarlig for indhold, der er beskyttet. Den anden nødvendigeRoller
at
håndterer en række roller, der giver os adgang.
Vi har brug for en repræsentation af denne struktur. Det er meget enkelt. Vi udvider typen React.PropsMedBørn
der har børn
egenskab. Du kan selvfølgelig tilføje denne egenskab manuelt til din type og udelade udvidelsen.
interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
}
Selve komponenten er også enkel. Vi vil genbruge harRolle
funktion her.
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.børn}
);
} ellers {
return ;
}
}
"`
Og jeg kunne sige stop her, men det ville være for nemt. Nu har vi en komponent, og vi kan bruge den til det yderste 😀.
Første skridt vil være eksternalisering af kontroller. nuværende bruger
er en hardcoded værdi. Jeg vil gerne indkapsle denne værdi
til en tjeneste, der "ved", hvordan man verificerer roller. Teknisk set betyder det, at vi flytter harRolle
funktion til en anden
klasse.
Jeg skaber en enkel grænseflade IGuardService
der kun har én egenskab - harRolle
.
export interface IGuardService {
checkRole: (roles: string[]) => boolean;
}
En simpel implementering kunne se sådan ud
class SimpleGuard implementerer IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
For at bruge det skal vi ændre IGuardEgenskaber
og anvendelse.
export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
guardService: IGuardService;
}
// ...
const AppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Kun administrator-komponent
Kun bruger-komponent
Administrator- og brugerkomponent
Element til generel brug
);
}
```
Nu ser komponenten sådan ud:
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.børn}
);
} ellers {
return ;
}
}
Meget bedre. VagtService
adskiller os fra den logik, der kontrollerer rollerne. Vi kan ændre det uden konsekvenser for vores
komponent. En almindelig brugssag er at bruge mock i tests og en "rigtig" implementering i produktionskoden.
Næste forbedring bliver håndtering af brugerdefinerede Forbudt
element. Den nuværende løsning gengiver et tomt element. Først er vi nødt til at
ændring IGuardProps
tilføjer en funktion, der skal gengives for det pågældende element.
export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Dette er en valgfri egenskab, og navnet slutter med et spørgsmålstegn. Så det kan være en funktion eller udefineret
. Vi er nødt til at
håndtere det i Vagt
komponent.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.børn}
);
} else if (props.forbidden === undefined) {
return ;
} else {
return (
{props.forbidden()}
);
}
}
// ...
export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Kun administrator-komponent
Kun bruger-komponent
Forbudt - kun moderator kan se dette
}>
Moderator-komponent
Administrator- og brugerkomponent
Element til generel brug
);
}
```
Tid til den sidste store ændring. Den nuværende version af komponenten understøtter kun roller som streng
. Vi kunne have flere forskellige
typer af egenskaber, som vi gerne vil kontrollere. Tal eller brugerdefinerede typer er ikke noget særligt. Jeg vil tilføje generisk understøttelse.
Første skridt er ændringer i IGuardService
grænseflade. Implementeringer vil afhænge af typen af den testede værdi. Det kan være
være hvad som helst, så grænsefladen bør håndtere det.
export interface IGuardService {
checkRole: (roles: ROLE[]) => boolean;
}
Nu tager den et array af ROLLE
generisk type. Vores enkle implementering vil ændre sig lidt.
class SimpleGuard implementerer IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
Vi er nødt til at tilføje en typeparameter, men vi kan forberede en implementering, der understøtter IRole
interface.
interface IRole {
navn: streng;
}
//...
class RoleGuardService implementerer IGuardService {
checkRole(roles: IRole[]): boolean {
lad fundet: IRole | undefined = roles.find(e => e === userWithRole.role);
return found !== undefined;
}
}
```
Andet trin er at udbrede denne ændring til IGuardProps
.
interface IGuardProps extends React.PropsWithChildren {
requiredRoles: ROLE[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Og henholdsvis til Vagt
komponent.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.børn}
);
} else if (props.forbidden === undefined) {
return ;
} else {
return (
{props.forbidden()}
);
}
}
Og vores brugsscenarier
export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
const roleService = new RoleGuardService();
return (
<header>
<nav>
<ul>
<Guard<IRole> requiredRoles={[{name: "ADMIN"}]} guardService={roleService}>.
<li>Komponent kun for administratorer</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>.
<li>Komponent kun for brugere</li>
</Guard>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
forbidden={() => <div>Forbudt - kun moderator kan se dette</div>}>
<li>Moderator-komponent</li>
</Guard>
<Guard<string> requiredRoles={["USER", "ADMIN"]} guardService={guardService}>.
<li>Administrator- og brugerkomponent</li>
</Guard>
<li>Generelt brugselement</li>
</ul>
</nav>
</header>
);
}
I dette eksempel bruger jeg begge implementeringer af IGuardservice
bare til illustrative formål. I rigtige brugssager skal du
bruger sandsynligvis kun én.
Den Vagt
kan være indlejret. Bare husk, at adgangen vil blive løst i rækkefølge fra den mest eksterne instans.
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>Komponent kun for administratorer</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>.
<li>Komponent kun for brugere</li>
</Guard>
<li>Administrator- og brugerkomponent</li>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
forbidden={() => <div>Forbudt - kun moderator kan se dette</div>}>
<li>Moderator-komponent</li>
</Guard>
</Guard>
<li>Generelt brugselement</li>
</ul>
</nav>
</header>
);
}
I ovenstående eksempel Moderator-komponent
kunne aldrig vises, fordi brugeren kun kan håndtere én rolle. Den første Vagt
grænser
roller til ADMIN
og BRUGER
så MODERATOR
vil aldrig bestå første kontrol.
Vi kan bygge specialiserede komponenter, der skjuler nogle egenskaber.
export const AdminGuard = (props: Omit) => {
return .
{props.children}
}
//...
export const SpecializedAppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Kun administrator-komponent
.
Kun bruger-komponent
Forbudt - kun moderator kan se dette
}>
Moderator-komponent
.
Administrator- og brugerkomponent
Element til generel brug
);
}
```
I dette tilfælde AdminGuard
foruddefinerer ADMIN
rolle. I konsekvenserne er vi nødt til eksplicit at definere typen af ROLLE
type
parameter.
I denne artikel viser jeg dig, hvordan du opretter og bruger Vagt
komponent i React. Vi starter med kompleks kode, der er svær at
læse og vedligeholde. Vi udvikler den til en mere udviklervenlig tilstand og introducerer brugerdefinerede funktionelle komponenter. Dernæst
udvide komponenten med ekstra funktioner, refaktorere udtrækningstjenesten og endelig tilføje generiske typer.
Endelig har vi en komponent, der kan indlejres, og som er nem at teste og vedligeholde.