För- och nackdelar med React
Varför är det värt att använda React? Vilka fördelar har detta JavaScript-bibliotek? För att ta reda på svaren dyk in i den här artikeln och upptäck de verkliga fördelarna med att använda React.
Lär dig hur du förenklar och förbättrar komponenternas synlighet i React med hjälp av villkorlig rendering och skyddskomponenter.
Idag skulle jag vilja diskutera hur man kan kontrollera komponentens synlighet i React. Men innan vi börjar finns det små
Ansvarsfriskrivning:
Den presenterade lösningen är inte särskilt säker när det gäller att skydda din applikation mot "hackare" (vilka de nu är).
Kom ihåg att du måste skydda dina slutpunkter och använda god praxis i applikationsdesignen. Den här lösningen gör bara
gör bara ditt arbete lite enklare.
En av de vanligaste funktionerna är att visa komponenter endast för ett antal användare som har vissa specifika rättigheter,
roller eller behörigheter. En vanlig lösning är att lägga till några om
s till kod, manuellt kontrollera villkoren och visa eller inte element.
Låt oss ta en titt på SimpleAppHuvud
komponent som innehåller få navigeringselement.
<!-- wp:paragraph -->
<p><code>typskript jsx<br>
export const SimpleAppHeader: FC = () => {<br>
returnera (<br>
<br>
<nav><br>
<ul><br>
{<br>
currentUser.role === "ADMIN" &&<br>
<li>Komponent endast för administratörer</li><br>
}<br>
{<br>
currentUser.role === "USER" &&<br>
<li>Enbart användarkomponent</li><br>
}<br>
}<br> {<br>
(currentUser.role === "ADMIN" || currentUser.role === "USER") &&<br>
<li>Enbart komponent för administratör och användare</li><br>
}<br>
<li>Generell användning av element</li><br>
</ul><br>
</nav><br>
</header><br>
)<br> <br>
}<br>
</code></p>
<!-- /wp:paragraph -->
Ser "inte illa" ut. Förmodligen kan du kapsla in kontroller i funktioner för att minska komplexiteten. Aktuell användare
är något objekt
som har roll
egendom, men det kan vara vad som helst som vi vill använda som föremål för vår kontrollmekanism.
Denna kod har vissa problem. Om projekt växer använder vi förmodligen dessa konstruktioner på många ställen. Så vi behöver kopiera,
på något sätt, villkor. Den här koden är svår att underhålla och ändra i framtiden. Speciellt när åtkomstreglerna ändras under
tid t.ex. vi behöver ändra Aktuell användare
till något annat. Det är mycket svårt att testa. Du måste skriva många tester
bara för att verifiera om ditt tillstånd är ok.
Dags att förenkla den här koden lite. Vi kan extrahera några metoder och göra koden kortare och mindre komplex:
const isAdmin = (role: string): boolean => roll === "ADMIN";
const isUser = (role: string): boolean => roll === "USER";
const isAdminOrUser = (role: string): boolean => isAdmin(role) || isUser(role);
export const SimplifiedAppHeader: FC = () => {
returnera (
{
isAdmin(currentUser.role) &&
Endast Admin-komponent
}
{
isUser(currentUser.role) &&
Endast användarkomponent
}
{
(isAdminOrUser(currentUser.role)) &&
Endast Admin- och User-komponent
}
Element för allmän användning
)
}
```
Det ser lovande ut. Vi minskar brus och upprepade rader. Koden blir mer läsbar och lättare att underhålla. Men ta en titt på
funktion isAdminOrUser
. Vi har bara två roller. Om vi inför en tredje roll måste vi skapa en annan uppsättning funktioner
som kombinerar roller. Dags för en ny version.
Låt införa funktionen harRoll
som kommer att vara ersättning för vår isX
funktioner.
const hasRole = (role: sträng, requiredRole: sträng[]): boolean => {
let found: string | undefined = requiredRole.find(s => role === s);
return found !== undefined;
}
export const FilteringAppHeader: FC = () => {
returnera (
{
hasRole(currentUser.role, ["ADMIN"]) &&
Endast Admin-komponent
}
{
hasRole(currentUser.role, ["USER"]) &&
Endast användarkomponent
}
{
hasRole(currentUser.role, ["ADMIN", "USER"]) &&
Endast Admin- och User-komponent
}
Element för allmän användning
)
}
```
Nu ser det bra ut. Vi har fortfarande villkor i html-delen av koden, men nu kan vi testa harRoll
funktion och lita på att den
kommer att användas med rätt uppsättning parametrar. Det är nu enklare att lägga till eller ändra roller. Vi använder en array som innehåller alla
roller som vi behöver ha på plats.
Denna lösning är dock bunden till Aktuell användare
objekt. Antagandet är att objektet på något sätt är globalt eller lättillgängligt i
var som helst i applikationen. Så vi kan försöka kapsla in det här. Naturligtvis kan vi flytta den till harRoll
funktion:
const hasRole = (requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => currentUser.role === s);
return found !== undefined;
}
Men det ger oss nästan ingenting.
Vakt
KomponentDags att skapa en komponent som kapslar in hela logiken. Jag döpte den till Vakt
och det är så här jag vill använda den.
export const GuardedAppHeader: FC = () => {
returnera (
</header
);
}
Komponent behöver två egenskaper. För det första barn
ansvarig för innehåll som är skyddat. Andra nödvändigaRoller
att
hantera en rad olika roller som ger oss tillgång.
Vi behöver en representation av denna struktur. Det är mycket enkelt. Vi utökar typen React.RekvisitaMedBarn
som har barn
egenskap. Naturligtvis kan du manuellt lägga till den egenskapen i din typ och utelämna extension.
interface IGuardProps extends React.PropsWithChildren {
requiredRoles: sträng[];
}
Själva komponenten är också enkel. Vi kommer att återanvända harRoll
funktion här.
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}
);
} annars {
returnera ;
}
}
"`
Och jag skulle kunna säga stopp här, men det skulle vara för lätt. Nu har vi en komponent och vi kan använda den till det yttersta 😀.
Första steget blir att externalisera kontrollerna. Aktuell användare
är ett hårdkodat värde. Jag skulle vilja kapsla in detta värde
till någon tjänst som "vet" hur man verifierar roller. Tekniskt sett innebär det att vi flyttar harRoll
funktion till en annan
klass.
Jag skapar ett enkelt gränssnitt IGuardService
som bara har en egenskap - harRoll
.
export interface IGuardService {
checkRole: (roles: string[]) => boolean;
}
Nu kan en enkel implementering se ut så här
class SimpleGuard implementerar IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
För att använda den måste vi ändra IGuardEgenskaper
och användningsområde.
export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: sträng[];
vaktService: IGuardService;
}
// ...
const AppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Endast Admin-komponent
Endast användarkomponent
Admin- och användarkomponent
Element för allmän användning
);
}
```
Nu ser komponenten ut som:
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.barn}
);
} annars {
returnera ;
}
}
Mycket bättre. Vakttjänst
separera oss från logik som kontrollerar roller. Vi kan ändra det utan konsekvenser för vår
komponent. Ett vanligt användningsfall är att använda mock i tester och viss "riktig" implementering i produktionskoden.
Nästa förbättring kommer att vara hantering av anpassade Förbjudet
element. Den nuvarande lösningen återger ett tomt element. Först måste vi
förändring IGuardProps
lägger till funktion som kommer att renderas för det elementet.
export interface IGuardProps extends React.PropsWithChildren {
requiredRoles: sträng[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Detta är en valfri egenskap, namnet slutar med ett frågetecken. Så det kan vara funktion eller odefinierad
. Vi behöver
hantera det i Vakt
komponent.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.barn}
);
} else if (props.forbidden === undefined) {
returnera ;
} annars {
returnera (
{rekvisita.förbjuden()}
);
}
}
// ...
export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
returnera (
Endast Admin-komponent
Endast användarkomponent
Förbjuden - endast moderator kan se detta
}>
Moderator-komponent
Admin- och användarkomponent
Element för allmän användning
);
}
```
Dags för den sista stora förändringen. Nuvarande version av komponenten stöder endast roller som sträng
. Vi skulle kunna ha flera olika
typer av egendom som vi vill kontrollera. Siffror eller anpassade typer är inget speciellt. Jag kommer att lägga till generiskt stöd.
Första steget är förändringar i IGuardService
gränssnitt. Implementationerna beror på vilken typ av värde som testas. Det kan vara
kan vara vad som helst, så gränssnittet bör hantera det.
export interface IGuardService {
checkRole: (roles: ROLE[]) => boolean;
}
Nu tar den en matris av ROLL
generisk typ. Vår enkla implementering kommer att förändras lite.
class SimpleGuard implementerar IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
Vi måste lägga till en typparameter, men vi kan förbereda en implementation som stöder IRole
gränssnitt.
gränssnitt IRole {
namn: sträng;
}
//...
class RoleGuardService implementerar IGuardService {
checkRole(roles: IRole[]): boolean {
låt found: IRole | undefined = roles.find(e => e === userWithRole.role);
return found !== undefined;
}
}
```
Andra steget är att sprida denna ändring till IGuardProps
.
interface IGuardProps extends React.PropsWithChildren {
requiredRoles: ROLE[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Och respektive till Vakt
komponent.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.barn}
);
} else if (props.forbidden === undefined) {
returnera ;
} annars {
returnera (
{rekvisita.förbjuden()}
);
}
}
Och våra användningsområden
export const AppHeader: FC = () => {
const guardService = ny SimpleGuard();
const roleService = new RoleGuardService();
return (
<header>
<nav>
<ul>
<Guard<IRole> requiredRoles={[{namn: "ADMIN"}]} guardService={roleService}>
<li>Komponent endast för administratörer</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>
<li>Endast användarkomponent</li>
</Guard>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
förbjudet={() => <div>Förbjudet - endast moderator kan se detta</div>}>
<li>Moderatorkomponent</li>
</Guard>
<Guard<string> requiredRoles={["USER", "ADMIN"]} guardService={guardService}>
<li>Admin- och användarkomponent</li>
</Guard>
<li>Allmänt användningselement</li>
</ul>
</nav>
</header>
);
}
I det här exemplet använder jag båda implementationerna av IGuardservice
bara för illustrativa ändamål. I verkliga användningsfall kan du
förmodligen bara använda en.
Den Vakt
kan vara nästlade. Kom bara ihåg att åtkomst kommer att lösas i ordning från den mest externa instansen.
export const NestAppHeader: FC = () => {
const guardService = new SimpleGuard();
returnera (
<header>
<nav>
<ul>
<Guard<string> requiredRoles={["USER", "ADMIN"]} guardService={guardService}>
<Guard<string> requiredRoles={["ADMIN"]} guardService={guardService}>
<li>Komponent endast för administratörer</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>
<li>Endast användarkomponent</li>
</Guard>
<li>Admin- och användarkomponent</li>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
förbjudet={() => <div>Förbjudet - endast moderator kan se detta</div>}>
<li>Moderatorkomponent</li>
</Guard>
</Guard>
<li>Allmänt användningselement</li>
</ul>
</nav>
</header>
);
}
I ovanstående exempel Moderatorkomponent
skulle aldrig kunna dyka upp, eftersom användaren bara kan hantera en roll. Första Vakt
gränser
roller till ADMIN
och ANVÄNDARE
, så MODERATOR
kommer aldrig att passera första kontrollen.
Vi kan bygga specialiserade komponenter som döljer vissa egenskaper.
export const AdminGuard = (props: Omit) => {
return {props.barn}
{props.barn}
}
//...
export const SpecializedAppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Endast Admin-komponent
Endast användarkomponent
Förbjudet - endast moderator kan se detta
}>
Moderator-komponent
Admin- och användarkomponent
Element för allmän användning
);
}
```
I detta fall AdminGuard
fördefiniera ADMIN
roll. Som en följd av detta måste vi uttryckligen definiera typen av ROLL
typ
parameter.
I den här artikeln visar jag dig hur du skapar och använder Vakt
komponent i React. Vi utgår från komplex kod som är svår att förstå och
läsa och underhålla. Vi utvecklar det till ett mer utvecklarvänligt tillstånd och introducerar anpassade funktionella komponenter. Nästa steg är
utöka komponenten med extra funktioner, omarbeta extraheringstjänsten och slutligen lägga till generiska typer.
Slutligen har vi en komponent som kan nästlas och som är lätt att testa och underhålla.