Fordeler og ulemper med React
Hvorfor er det verdt å bruke React? Hvilke fordeler har dette JavaScript-biblioteket? For å finne svarene kan du dykke ned i denne artikkelen og oppdage de virkelige fordelene ved å bruke React.
Lær hvordan du kan forenkle og forbedre komponentsynligheten i React ved hjelp av betinget gjengivelse og beskyttelseskomponenter.
I dag vil jeg gjerne diskutere hvordan man kan kontrollere komponentens synlighet i React. Men før vi begynner er det en liten
Ansvarsfraskrivelse:
Den presenterte løsningen er ikke særlig sikker når det gjelder å beskytte applikasjonen mot "hackere" (hvem det nå enn er).
Husk at du må beskytte endepunktene dine og bruke god praksis i applikasjonsdesign. Denne løsningen gjør bare
gjør bare arbeidet ditt litt enklere.
En av de vanligste funksjonene er å vise komponenter kun for en gruppe brukere som har bestemte rettigheter,
roller eller rettigheter. En vanlig løsning er å legge til noen hviss til kode, sjekk forholdene manuelt og vis eller ikke elementer.
La oss ta en titt på SimpleAppHeader komponent som inneholder få navigasjonselementer.
<!-- 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>Bare administrator-komponent</li><br>
}<br><br>
{<br>
currentUser.role === "USER" &&<br> <li>Bare brukerkomponent</li><br>
<li>Bare brukerkomponent</li><br> }<br> {<br> currentUser.role === "USER" &&<li><br>
}<br>
{<br>
(currentUser.role === "ADMIN" || currentUser.role === "USER") &&<br>
<li>Komponent kun for administrator og bruker</li><br> }<br> {<br> (currentUser.
}<br><br>
<li>Generell bruk av elementet</li><br>
</ul><br> </ul><br>
</nav><br>
</header><br>
)<br> <br>
}<br><br>
</code></p>
<!-- /wp:paragraph -->
Ser "ikke så verst" ut. Sannsynligvis kan du kapsle sjekkene inn i funksjoner for å redusere kompleksiteten. nåværendeBruker er et objekt
som har rolle egenskap, men det kan være hva som helst som vi ønsker å bruke som gjenstand for kontrollmekanismen vår.
Denne koden har noen problemer. Hvis prosjekt vokser, bruker vi sannsynligvis den konstruksjonen mange steder. Så vi må kopiere,
på en eller annen måte, betingelser. Denne koden er vanskelig å vedlikeholde og endre i fremtiden. Spesielt når tilgangsreglene endres i løpet av
tid, f.eks. må vi endre nåværendeBruker til noe annet. Det er veldig vanskelig å teste. Du må skrive mange tester
bare for å sjekke om tilstanden din er ok.
På tide å forenkle denne koden litt. Vi kan trekke ut noen metoder og gjø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 Admin-komponent
}
{
isUser(currentUser.role) &&
Kun bruker-komponent
}
{
(isAdminOrUser(currentUser.role)) && (isAdminOrUser(currentUser.role))
Kun Admin- og brukerkomponent
}
Element for generell bruk
)
}
```
Det ser lovende ut. Vi reduserer støy og gjentatte linjer. Koden er mer lesbar og enklere å vedlikeholde. Men ta en titt på
funksjon isAdminOrUser. Vi har bare to roller. Hvis vi innfører en tredje rolle, må vi opprette et nytt sett med funksjoner
som kombinerer roller. På tide med en ny versjon.
La oss introdusere funksjonen hasRole som vil være en erstatning for vår isX funksjoner.
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 Admin-komponent
}
{
hasRole(currentUser.role, ["USER"]) &&
Kun bruker-komponent
}
{
hasRole(currentUser.role, ["ADMIN", "USER"]) &&
Kun Admin- og User-komponent
}
Element for generell bruk
)
}
```
Nå ser det bra ut. Vi har fortsatt betingelser i html-delen av koden, men nå kan vi teste hasRole funksjon og stoler på at den
vil bli brukt med riktig sett med parametere. Det er nå enklere å legge til eller endre roller. Vi bruker en matrise som inneholder alle
roller som vi trenger på plass.
Denne løsningen er imidlertid bundet til nåværendeBruker objekt. Forutsetningen er at objektet på en eller annen måte er globalt eller lett tilgjengelig i
et hvilket som helst sted i applikasjonen. Så vi kan prøve å innkapsle dette. Vi kan selvfølgelig flytte den til hasRole funksjon:
const hasRole = (requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => currentUser.role === s);
return found !== undefined;
}
Men det gir oss nesten ingenting.
Vakt KomponentPå tide å lage en komponent som kapsler inn hele logikken. Jeg kalte den Vakt og det er slik jeg vil bruke den.
export const GuardedAppHeader: FC = () => {
return (
</header
);
}
Komponent trenger to egenskaper. For det første barn ansvarlig for innhold som er beskyttet. Andre requiredRoles at
håndtere en rekke roller som gir oss tilgang.
Vi trenger en representasjon av denne strukturen. Det er veldig enkelt. Vi utvider typen React.rekvisittermedbarn som har barn
egenskapen. Du kan selvfølgelig legge til denne egenskapen manuelt i typen og utelate utvidelsen.
interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
}
Selve komponenten er også enkel. Vi vil gjenbruke hasRole funksjon 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.barn}
);
} ellers {
return ;
}
}
"`
Og jeg kunne sagt stopp her, men det ville blitt for enkelt. Nå har vi komponenten, og vi kan bruke den til det ytterste 😀.
Første skritt vil være eksternalisering av kontroller. nåværendeBruker er en hardkodet verdi. Jeg vil gjerne innkapsle denne verdien
til en tjeneste som "vet" hvordan rollene skal verifiseres. Teknisk sett betyr det at vi flytter hasRole funksjon til en annen
klasse.
Jeg lager et enkelt grensesnitt IGuardService som bare har én egenskap - hasRole.
export interface IGuardService {
checkRole: (roles: string[]) => boolean;
}
Nå kan en enkel implementering se slik ut
class SimpleGuard implementerer IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
For å bruke den må vi endre IGuardEgenskaper og brukstilfelle.
export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
guardService: IGuardService;
}
// ...
const AppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Kun administrator-komponent
Kun brukerkomponent
Admin- og brukerkomponent
Element for generell bruk
);
}
```
Nå ser komponenten slik ut:
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.children}
);
} ellers {
return ;
}
}
Mye bedre. GuardService skiller oss fra logikken som kontrollerer rollene. Vi kan endre den uten at det får konsekvenser for vår
komponent. Det er vanlig å bruke mock i tester og en "ekte" implementering i produksjonskoden.
Neste forbedring vil være håndtering av egendefinerte Forbudt element. Den nåværende løsningen gjengir et tomt element. Først må vi
endring IGuardProps legge til funksjon som vil bli gjengitt det elementet.
export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Dette er en valgfri egenskap, og navnet slutter med et spørsmålstegn. Så det kan være funksjon eller udefinert. Vi trenger å
håndtere det i Vakt komponent.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.children}
);
} else if (props.forbidden === undefined) {
return ;
} else {
return (
{rekvisita.forbudt()}
);
}
}
// ...
export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Kun administrator-komponent
Kun brukerkomponent
Forbudt - bare moderator kan se dette
}>
Moderator-komponent
Administrator- og brukerkomponent
Element for generell bruk
);
}
```
På tide med den siste store endringen. Nåværende versjon av komponenten støtter kun roller som streng. Vi kan ha flere forskjellige
typer egenskaper som vi ønsker å sjekke. Tall eller egendefinerte typer er ikke noe spesielt. Jeg vil legge til generisk støtte.
Første skritt er endringer i IGuardService grensesnitt. Implementeringene vil avhenge av typen testet verdi. Det kan
være hva som helst, så grensesnittet bør håndtere det.
export interface IGuardService {
checkRole: (roles: ROLE[]) => boolean;
}
Nå tar den en matrise av ROLLE generisk type. Vår enkle implementering vil endre seg litt.
class SimpleGuard implementerer IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
Vi må legge til en typeparameter, men vi kan forberede en implementering som støtter IRole grensesnitt.
grensesnitt IRole {
navn: string;
}
//...
class RoleGuardService implementerer IGuardService {
checkRole(roles: IRole[]): boolean {
let found: IRole | undefined = roles.find(e => e === userWithRole.role);
return found !== undefined;
}
}
```
Det andre trinnet er å videreføre denne endringen til IGuardProps.
interface IGuardProps extends React.PropsWithChildren {
requiredRoles: ROLE[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Og henholdsvis til Vakt komponent.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.children}
);
} else if (props.forbidden === undefined) {
return ;
} else {
return (
{rekvisita.forbudt()}
);
}
}
Og brukstilfellene våre
export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
const roleService = new RoleGuardService();
return (
<header>
<nav>
<ul>
<Guard<IRole> requiredRoles={[{navn: "ADMIN"}]} guardService={roleService}>
<li>Kun administrator-komponent</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>
<li>Kun brukerkomponent</li>
</Guard>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
forbidden={() => <div>Forbudt - bare moderator kan se dette</div>}>
<li>Moderatorkomponent</li>
</Guard>
<Guard<string> requiredRoles={[["USER", "ADMIN"]} guardService={guardService}>.
<li>Administrator- og brukerkomponent</li>
</Guard>
<li>Generelt brukselement</li>
</ul>
</nav>
</header>
);
}
I dette eksempelet bruker jeg begge implementasjonene av IGuardservice bare for illustrasjonsformål. I reelle brukstilfeller må du
sannsynligvis bare bruke én.
Den Vakt kan være nestet. Bare husk at tilgang vil bli løst i rekkefølge fra den mest eksterne instansen.
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>Kun administrator-komponent</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>
<li>Kun brukerkomponent</li>
</Guard>
<li>Administrator- og brukerkomponent</li>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
forbidden={() => <div>Forbudt - bare moderator kan se dette</div>}>
<li>Moderatorkomponent</li>
</Guard>
</Guard>
<li>Generelt brukselement</li>
</ul>
</nav>
</header>
);
}
I eksempelet ovenfor Moderatorkomponent aldri kunne vises, fordi brukeren bare kan håndtere én rolle. Første Vakt grenser
roller til ADMIN og BRUKER, så MODERATOR vil aldri passere første sjekk.
Vi kan bygge spesialiserte komponenter som skjuler enkelte egenskaper.
export const AdminGuard = (props: Omit) => {
return {props.barn}>.
{props.children}
}
//...
export const SpecializedAppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Kun administrator-komponent
Kun brukerkomponent
Forbudt - bare moderator kan se dette
}>
Moderator-komponent
Administrator- og brukerkomponent
Element for generell bruk
);
}
```
I dette tilfellet AdminGuard forhåndsdefinere ADMIN rolle. Som en konsekvens av dette må vi eksplisitt definere typen ROLLE type
parameter.
I denne artikkelen viser jeg deg hvordan du oppretter og bruker Vakt komponent i React. Vi tar utgangspunkt i kompleks kode som er vanskelig å
lese og vedlikeholde. Vi utvikler den til en mer utviklervennlig tilstand og introduserer tilpassede funksjonelle komponenter. Deretter
utvide komponenten med ekstra funksjonalitet, refaktorere uttrekkstjenesten og til slutt legge til generiske typer.
Til slutt har vi en komponent som kan nestes, og som er enkel å teste og vedlikeholde.
