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 hvis
s 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.