React privalumai ir trūkumai
Kodėl verta naudoti React? Kokių privalumų turi ši JavaScript biblioteka? Norėdami sužinoti atsakymus, pasinerkite į šį straipsnį ir sužinokite tikruosius React naudojimo privalumus.
Sužinokite, kaip supaprastinti ir pagerinti komponentų matomumą React naudojant sąlyginį atvaizdavimą ir apsauginius komponentus.
Šiandien norėčiau aptarti, kaip kontroliuoti komponento matomumas React. Bet prieš pradėdami yra mažas
Atsakomybės apribojimas:
Pateiktas sprendimas nėra labai saugus, t. y. neapsaugo jūsų programos nuo "įsilaužėlių" (kad ir kas jie būtų).
Nepamirškite, kad reikia apsaugoti savo galinius taškus ir taikyti gerąją taikomosios programos projektavimo praktiką. Šis sprendimas tik
šiek tiek palengvina jūsų darbą.
Viena iš dažniausiai pasitaikančių funkcijų - rodyti komponentą tik tam tikriems naudotojams, turintiems tam tikras konkrečias teises,
vaidmenis ar privilegijas. Įprastas sprendimas - pridėti keletą jeiį kodas, rankiniu būdu tikrinti sąlygas ir rodyti arba nerodyti elementus.
Leiskite pažvelgti į SimpleAppHeader komponentas, kuriame yra keletas navigacijos elementų.
<!-- wp:paragraph -->
<p><code>typescript jsx<br>
export const SimpleAppHeader: FC = () => {<br>
grąžinti (<br>
<header><br>
<nav><br>
<ul><br>
{<br>
currentUser.role === "ADMIN" &&<br>
<li>Tik administratoriaus komponentas</li><br>
}<br>
{<br>
currentUser.role === "USER" &&<br>
<li>Tik naudotojo komponentas</li><br>
}<br>
{<br>
(currentUser.role === "ADMIN" || currentUser.role === "USER") &&<br>
<li>Tik administratoriaus ir naudotojo komponentas</li><br>
}<br>
<li>Bendrojo naudojimo elementas</li><br>
</ul><br>
</nav><br>
</header><br>
)<br>
}<br>
</code></p>
<!-- /wp:paragraph -->
Atrodo "neblogai". Tikriausiai, norint sumažinti sudėtingumą, būtų galima patikras įtraukti į funkcijas. currentUser yra tam tikras objektas
kuris turi vaidmuo savybė, tačiau tai gali būti bet kas, ką norėtume naudoti kaip kontrolės mechanizmo objektą.
Šis kodas turi tam tikrų problemų. Jei projektas auga, mes tikriausiai naudojame šias konstrukcijas daugelyje vietų. Taigi mums reikia kopijuoti,
kažkaip, sąlygos. Šį kodą sunku prižiūrėti ir ateityje keisti. Ypač kai prieigos taisyklės keičiasi
laikas, pvz., turime pakeisti currentUser į ką nors kita. Tai labai sunku patikrinti. Reikia parašyti daug testų.
tik norėdami patikrinti, ar jūsų būklė yra tinkama.
Laikas šiek tiek supaprastinti šį kodą. Galime išskirti keletą metodų ir padaryti kodą trumpesnį ir ne tokį sudėtingą:
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) &&
Tik administratoriaus komponentas
}
{
isUser(currentUser.role) &&
Tik naudotojo komponentas
}
{
(isAdminOrUser(currentUser.role)) &&
Tik administratoriaus ir naudotojo komponentas
}
Bendrojo naudojimo elementas
)
}
```
Atrodo daug žadantis. Mes mažiname triukšmą od pakartoti linijas. Kodas labiau skaitomas ir lengviau prižiūrimas. Tačiau pažvelkite į
funkcija isAdminOrUser. Turime tik du vaidmenis. Jei įvesime trečią vaidmenį, turėsime sukurti kitą funkcijų rinkinį.
kuris sujungia vaidmenis. Laikas kitai versijai.
Įveskime funkciją hasRole kuris pakeis mūsų isX funkcijos.
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"]) &&
Tik administratoriaus komponentas
}
{
hasRole(currentUser.role, ["USER"]) &&
Tik naudotojo komponentas
}
{
hasRole(currentUser.role, ["ADMIN", "USER"]) &&
Tik administratoriaus ir naudotojo komponentas
}
Bendrojo naudojimo elementas
)
}
```
Dabar atrodo gerai. Vis dar turime sąlygas html kodo dalyje, bet dabar galime testuoti hasRole funkcija ir pasitikėjimas, kad ji
bus naudojamas teisingas parametrų rinkinys. Dabar lengviau pridėti arba keisti vaidmenis. Naudojame masyvą, kuriame yra visi
vaidmenis, kurių mums reikia.
Tačiau šis sprendimas yra susijęs su currentUser objektas. Darytina prielaida, kad objektas yra globalus arba lengvai pasiekiamas
bet kurioje taikymo vietoje. Taigi galime pabandyti tai įkapsuliuoti. Žinoma, galime perkelti jį į hasRole funkcija:
const hasRole = (requiredRole: string[]): boolean => {
let found: string | undefined = requiredRole.find(s => currentUser.role === s);
return found !== undefined;
}
Tačiau tai suteikia mus beveik nieko.
Apsauga KomponentasLaikas sukurti komponentą, kuris apima visą logiką. Pavadinau jį Apsauga ir noriu jį naudoti taip.
export const GuardedAppHeader: FC = () => {
return (
);
}
Komponentui reikia dviejų savybių. Pirmoji vaikai atsakingas už saugomą turinį. Antrasis requiredRoles kad
tvarkyti vaidmenų masyvą, kuris suteikia mums prieigą.
Mums reikia šios struktūros atstovavimo. Tai labai paprasta. Mes išplečiame tipą React.Rekvizitai su vaikais kuris turi vaikai
nuosavybė. Žinoma, galite rankiniu būdu pridėti šią savybę prie savo tipo ir praleisti plėtinį.
sąsaja IGuardProps plečia React.PropsWithChildren {
requiredRoles: string[];
}
Pats komponentas taip pat yra paprastas. Mes pakartotinai panaudosime hasRole funkcija čia.
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 {
grąžinti ;
}
}
"`
Galėčiau pasakyti, kad čia reikia sustoti, bet tai būtų per daug paprasta. Dabar mes turime komponentą ir galime juo naudotis iki kraštutinumo 😀
Pirmasis žingsnis - patikrinimų perkėlimas į išorę. currentUser yra kietai užkoduota reikšmė. Norėčiau šią reikšmę užkoduoti
į tam tikrą tarnybą, kuri "žinos", kaip patikrinti vaidmenis. Techniškai tai reiškia, kad mes perkeliame hasRole funkciją į kitą
klasė.
Aš kuriu paprastą sąsają IGuardService kuris turi tik vieną savybę - hasRole.
eksporto sąsaja IGuardService {
checkRole: (roles: string[]) => boolean;
}
Dabar paprastas įgyvendinimas galėtų atrodyti taip
klasė SimpleGuard įgyvendina IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
Norėdami jį naudoti, turime pakeisti IGuardProperties ir naudojimo atvejis.
eksportas sąsaja IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
guardService: IGuardService;
}
// ...
const AppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Tik administratoriaus komponentas
Tik naudotojo komponentas
Administratoriaus ir naudotojo komponentas
Bendrojo naudojimo elementas
);
}
```
Dabar komponentas atrodo taip:
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.children}
);
} else {
grąžinti ;
}
}
Daug geriau. GuardService atskirti mus nuo logikos, kuri tikrina vaidmenis. Galime ją keisti be pasekmių mūsų
komponentas. Dažniausiai bandymuose naudojamas imitacinis komponentas, o gamybiniame kode - "tikrasis".
Kitas patobulinimas - pasirinktinių Draudžiama elementas. Dabartinis sprendimas atvaizduoja tuščią elementą. Pirmiausia reikia
keisti IGuardProps pridedant funkciją, kuri bus atvaizduojama tam elementui.
eksportas sąsaja IGuardProps extends React.PropsWithChildren {
requiredRoles: string[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Tai neprivaloma savybė, pavadinimas baigiasi klausimo ženklo ženklu. Taigi tai gali būti funkcija arba neapibrėžtas. Mums reikia
tvarkyti jį Apsauga komponentas.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.children}
);
} else if (props.forbidden === undefined) {
grąžinti ;
} else {
grąžinti (
{props.forbidden()}
);
}
}
// ...
export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Tik administratoriaus komponentas
Tik naudotojo komponentas
Draudžiama - tai gali matyti tik moderatorius
}>
Moderatoriaus komponentas
Administratoriaus ir naudotojo komponentas
Bendrojo naudojimo elementas
);
}
```
Laikas paskutiniams dideliems pokyčiams. Dabartinės versijos komponentas palaiko tik tokius vaidmenis eilutė. Galime turėti kelis skirtingus
turto tipai, kuriuos norėtume patikrinti. Skaičiai arba pasirinktiniai tipai nėra nieko ypatingo. Aš pridėsiu bendrinių tipų palaikymą.
Pirmasis žingsnis - pokyčiai IGuardService sąsaja. Įgyvendinimas priklausys nuo testuojamos vertės tipo. Tai gali būti
būti bet kas, todėl sąsaja turėtų būti tvarkoma.
eksporto sąsaja IGuardService {
checkRole: (roles: ROLE[]) => boolean;
}
Dabar jis užima masyvą ROLE bendrinis tipas. Mūsų paprastas įgyvendinimas šiek tiek pasikeis.
klasė SimpleGuard įgyvendina IGuardService {
checkRole(roles: string[]): boolean {
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
Mums reikia pridėti tipo parametrą, tačiau galime parengti realizaciją, kuri palaiko IRole sąsaja.
sąsaja IRole {
name: string;
}
//...
klasė RoleGuardService implements IGuardService {
checkRole(roles: IRole[]): boolean {
leiskite rasti: IRole | undefined = roles.find(e => e === userWithRole.role);
return found !== undefined;
}
}
```
Antrasis žingsnis - perkelti šį pakeitimą į IGuardProps.
sąsaja IGuardProps extends React.PropsWithChildren {
requiredRoles: ROLE[];
guardService: IGuardService;
forbidden?: () => React.ReactNode;
}
Ir atitinkamai į Apsauga komponentas.
export const Guard = (props: IGuardProps) => {
if (props.guardService.checkRole(props.requiredRoles)) {
return (
{props.children}
);
} else if (props.forbidden === undefined) {
grąžinti ;
} else {
grąžinti (
{props.forbidden()}
);
}
}
Ir mūsų naudojimo atvejai
export const AppHeader: FC = () => {
const guardService = new SimpleGuard();
const roleService = new RoleGuardService();
return (
<header>
<nav>
<ul>
<Guard<IRole> requiredRoles={[{{pavadinimas: "ADMIN"}]} guardService={roleService}>
<li>Tik administratoriaus komponentas</li>
</Guard>
<Guard<string> requiredRoles={{["USER"]} guardService={guardService}>
<li>Tik naudotojo komponentas</li>
</Guard>
<Guard<string> requiredRoles={{["MODERATOR"]} guardService={guardService}
draudžiama={() => <div>Draudžiama - tai gali matyti tik moderatorius</div>}>
<li>Moderatoriaus komponentas</li>
</Guard>
<Guard<string> requiredRoles={{["USER", "ADMIN"]} guardService={guardService}>
<li>Administratoriaus ir naudotojo komponentas</li>
</Guard>
<li>Bendrojo naudojimo elementas</li>
</ul>
</nav>
</header>
);
}
Šiame pavyzdyje aš naudoju abi įgyvendinimo IGuardservice tik iliustraciniais tikslais. Tikrais naudojimo atvejais
tikriausiai naudosite tik vieną.
Svetainė Apsauga gali būti įterptas. Tik nepamirškite, kad prieiga bus sprendžiama eilės tvarka nuo daugumos išorinių instancijų.
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>Tik administratoriaus komponentas</li>
</Guard>
<Guard<string> requiredRoles={{["USER"]} guardService={guardService}>
<li>Tik naudotojo komponentas</li>
</Guard>
<li>Administratoriaus ir naudotojo komponentas</li>
<Guard<string> requiredRoles={{["MODERATOR"]} guardService={guardService}
draudžiama={() => <div>Draudžiama - tai gali matyti tik moderatorius</div>}>
<li>Moderatoriaus komponentas</li>
</Guard>
</Guard>
<li>Bendrojo naudojimo elementas</li>
</ul>
</nav>
</header>
);
}
Pirmiau pateiktame pavyzdyje Moderatoriaus komponentas niekada negalėjo pasirodyti, nes naudotojas gali atlikti tik vieną vaidmenį. Pirmasis Apsauga ribos
vaidmenis į ADMIN ir VARTOTOJAS, todėl MODERATORIUS niekada nepraeis pirmojo patikrinimo.
Galime kurti specializuotus komponentus, kurie paslepia kai kurias savybes.
export const AdminGuard = (props: Omit) => {
return
{props.children}
}
//...
export const SpecializedAppHeader: FC = () => {
const guardService = new SimpleGuard();
return (
Tik administratoriaus komponentas
Tik naudotojo komponentas
Draudžiama - tai gali matyti tik moderatorius
}>
Moderatoriaus komponentas
Administratoriaus ir naudotojo komponentas
Bendrojo naudojimo elementas
);
}
```
Šiuo atveju "AdminGuard" iš anksto apibrėžti ADMIN vaidmuo. Dėl pasekmių turime aiškiai apibrėžti tipą ROLE tipas
parametras.
Šiame straipsnyje parodysiu, kaip sukurti ir naudoti Apsauga React komponentas. Pradedame nuo sudėtingo kodo, kurį sunku
skaityti ir prižiūrėti. Mes vystome jį į daugiau kūrėjas draugišką būseną ir įdiegti pasirinktinį funkcinį komponentą. Toliau mes
išplėsti komponentą, pridedant papildomų funkcijų, pertvarkyti ištraukimo paslaugą ir galiausiai pridėti generinių tipų.
Galiausiai turime komponentą, kurį galima įterpti į lizdą, yra lengva testuoti ir prižiūrėti.
