Reactの長所と短所
なぜReactを使う価値があるのか?このJavaScriptライブラリにはどんな利点があるのか?その答えを見つけるために、この記事に飛び込んで、Reactを使う本当の利点を発見してください。
条件付きレンダリングとガード・コンポーネントを使用して、Reactでコンポーネントの可視性を簡素化し、改善する方法を紹介します。
今日は、そのコントロール方法についてお話したいと思う。 Reactのコンポーネントの可視性.しかし、その前に小さなことがある。
免責事項
提示されたソリューションは、あなたのアプリケーションを「ハッカー」(誰であろうと)から守るという意味では、あまり安全ではありません。
エンドポイントを保護し、アプリケーションの設計に良い習慣を用いる必要があることを忘れないでください。この解決策は
あなたの仕事を少し楽にするだけです。
最も一般的な機能の1つは、特定の権限を持つユーザーのみにコンポーネントを表示することです、
ロールや権限を追加することです。一般的な解決策は もし
への コード手動で条件をチェックし、エレメントを表示するかしないかを決める。
を見てみよう。 シンプルAppヘッダー
コンポーネントは、ナビゲーション要素をほとんど含まない。
<!-- wp:paragraph -->
<p><code>タイプスクリプト jsx<br>
export const SimpleAppHeader:FC = () => {<br
return (<br>
<header><br>
<nav><br>
<ul><br>
{<br>
currentUser.role === "ADMIN" &&<br> <br
<li>管理者のみのコンポーネント</li><br>。
</li><li> </li><li> </li><br
{<br>
currentUser.role === "USER" &&<br> <li>管理者専用コンポーネント</li><br> <li>管理者専用コンポーネント</li><br> <li>管理者専用コンポーネント</li><br
<li>ユーザーのみのコンポーネント</li><br>。
}<br
{<br>
(currentUser.role === "ADMIN" || currentUser.role === "USER") &&<<br> <li>管理者・ユーザー専用コンポーネント</li><br
<li>管理者とユーザーのみのコンポーネント</li><br>。
<li>一般的な用法要素</li><br>。
</ul><br
</nav><br
</header><br
)<br> <br> <li>一般的な利用要素</li><ul><br> </header><br>。
</li><ul><br> </header><br> )<br>
</code></p>
<!-- /wp:paragraph -->
見た目は「悪くない」。おそらく、複雑さを減らすためにチェックを関数にカプセル化できるだろう。 カレントユーザー
はあるオブジェクト
それは 役割
しかし、コントロール・メカニズムとして使いたいものであれば、何でも構わない。
このコードにはいくつかの問題がある。もし プロジェクト 成長するにつれて、私たちは多くの場所でその構文を使うようになるだろう。だからコピーする必要がある、
どういうわけか、コンディション。このコードはメンテナンスが難しく、将来的に変更される可能性もある。特に
時間 カレントユーザー
を別のものに変える。テストするのはとても難しい。多くのテストを書く必要がある
あなたのコンディションが問題ないかどうかを確認するためにね
このコードを少し単純化しよう。いくつかのメソッドを抽出して、コードをより短く、より複雑にすることができる:
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)&&を返します。
管理者のみのコンポーネント
}
{
isUser(currentUser.role)&&の場合。
ユーザ専用コンポーネント
}
{
(isAdminOrUser(currentUser.role))&&。
管理者とユーザーのみのコンポーネント
}
一般利用要素
)
}
```
期待できそうだ。繰り返し行のノイズを減らすことができる。コードは読みやすくなり、メンテナンスも容易になる。しかし
機能 isAdminOrUser
.我々は2つの役割しか持っていない。もし3つ目のロールを導入するのであれば、別の関数セットを作成する必要があります。
役割を組み合わせた別のバージョンへ。
関数 ハズロール
その代わりとなるのが isX
の機能がある。
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"]) && (管理者専用コンポーネント)
管理者のみのコンポーネント
}
{
hasRole(currentUser.role, ["USER"]) &&管理者専用コンポーネント } {管理者のみ
ユーザのみのコンポーネント
}
{
hasRole(currentUser.role, ["ADMIN", "USER"]) &&.
管理者とユーザーのみのコンポーネント
}
一般利用要素
)
}
```
これで見た目は良くなった。コードのhtml部分にはまだ条件があるが、これでテストできるようになった。 ハズロール
その機能と信頼
は正しいパラメータセットで使用されます。ロールの追加や変更が簡単になりました。すべての
我々が必要としている役割だ。
しかし、この解決策は カレントユーザー
オブジェクトにアクセスできます。前提として、オブジェクトは何らかの形でグローバルであるか、あるいは
アプリケーションのどこにでも。だから、これをカプセル化することができる。もちろん、これを ハズロール
関数である:
const hasRole = (requiredRole: string[]): boolean => { 以下のようになります。
let found: string | undefined = requiredRole.find(s => currentUser.role === s);
return found !== undefined;
}
しかし、それではほとんど何も得られない。
ガード
コンポーネントロジック全体をカプセル化するコンポーネントを作る時が来た。名前は ガード
そして、このように使いたい。
export const GuardedAppHeader:FC = () => {
return (
<ヘッダー
);
}
コンポーネントには2つの特性が必要だ。まず 子供たち
保護されているコンテンツに責任がある。第二 必須ロール
その
アクセス権を与える役割の配列を扱う。
この構造体の表現が必要だ。それは非常に簡単である。型 React.小道具の子供たち
それは 子供たち
プロパティを使用します。もちろん、手動でそのプロパティをタイプに追加し、拡張子を省略することもできる。
interface IGuardProps extends React.PropsWithChildren { インターフェース IGuardProps.
requiredRoles: string[];
}
コンポーネント自体もシンプルだ。私たちは ハズロール
関数はここにある。
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)) { { if (hasRole(props.requiredRoles))
return (
{props.children}
);
} else {
return ;
}
}
"`
ここで止めることもできるが、簡単すぎるだろう。今、私たちはコンポーネントを持っている。
最初のステップはチェックの外部化である。 カレントユーザー
はハードコードされた値です。この値をカプセル化したい。
ロールの検証方法を "知っている "何らかのサービスに。技術的には ハズロール
関数を別の
クラスである。
シンプルなインターフェースを作る IGuardService
という1つのプロパティしか持たない。 ハズロール
.
エクスポート・インターフェース IGuardService {
checkRole: (roles: string[]) => boolean;
}
簡単な実装は次のようになる。
class SimpleGuard implements IGuardService { (クラスSimpleGuardはIGuardServiceを実装する)
checkRole(roles: string[]): boolean { 次のようにします。
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
これを使うには、次のように変更する必要がある。 IGuardProperties
とユースケース。
export interface IGuardProps extends React.PropsWithChildren { 次のようになります。
requiredRoles: string[];
guardService:IGuardService;
}
// ...
const AppHeader:FC = () => {
const guardService = new SimpleGuard();
return (
管理者専用コンポーネント
ユーザ専用コンポーネント
管理者とユーザーのコンポーネント
一般利用要素
);
}
```
今のコンポーネントはこうだ:
export const Guard = (props: IGuardProps) => { if (props.guardService.checkRole(props.requiredRoles))
if (props.guardService.checkRole(props.requiredRoles)) { (props.guardService.checkRole(props.requiredRoles))
return (
{props.children}を返します。
);
} else {
return ;
}
}
ずっといい。 ガードサービス
役割をチェックするロジックから私たちを切り離す。私たちは
コンポーネントを使用する。一般的なユースケースは、テストではモックを使い、本番コードではいくつかの "本物の "実装を使うというものだ。
次の改善点は、カスタムの取り扱いだ。 禁止
要素を表示します。現在の解決策は、空の要素をレンダリングします。まず
変更 IGuardProps
その要素をレンダリングする関数を追加する。
export interface IGuardProps extends React.PropsWithChildren {.
requiredRoles: string[];
guardService:IGuardService;
forbidden?: () => React.ReactNode;
}
これはオプションのプロパティで、名前はクエスチョンマークで終わります。つまり、関数または 未定義
.我々は、次のことが必要だ。
で処理する。 ガード
コンポーネントを使用している。
export const Guard = (props: IGuardProps) => { もし (props.guardService.checkRole(props.requiredRoles))
if (props.guardService.checkRole(props.requiredRoles)) { (props.guardService.checkRole(props.requiredRoles))
return (
{props.children}を返します。
);
} else if (props.forbidden === undefined) { {.
return ;
} else {
return ()
{props.forbidden()}を返します。
);
}
}
// ...
export const AppHeader:FC = () => {
const guardService = new SimpleGuard();
return (
管理者専用コンポーネント
ユーザ専用コンポーネント
禁止 - モデレーターのみ閲覧可
}>
モデレーターコンポーネント
管理者とユーザーのコンポーネント
一般利用要素
);
}
```
最後の大きな変化の時です。現バージョンのコンポーネントは ストリング
.私たちは、複数の異なる
チェックしたいプロパティのタイプ。数字やカスタム・タイプは特別なものではない。ジェネリックのサポートを追加します。
最初のステップは IGuardService
インタフェースを実装する。実装はテストされる値のタイプに依存する。それは
だから、インターフェイスがそれを処理するべきだ。
export interface IGuardService { 次のようにします。
checkRole: (roles: ROLE[]) => boolean;
}
の配列を取るようになった。 役割
ジェネリック型。私たちの単純な実装は少し変わる。
class SimpleGuard implements IGuardService { 次のようになります。
checkRole(roles: string[]): boolean { 次のようにします。
let found: string | undefined = roles.find(e => e === currentUser.role);
return found !== undefined;
}
}
型パラメータを追加する必要があるが、以下のような実装を用意することもできる。 イロール
インターフェイスを使用している。
インターフェース IRole {
name: 文字列;
}
//...
class RoleGuardService implements IGuardService { {...
checkRole(roles: IRole[]): boolean {.
let found:IRole | undefined = roles.find(e => e === userWithRole.role);
return found !== undefined;
}
}
```
第二のステップは、この変更を IGuardProps
.
interface IGuardProps extends React.PropsWithChildren {.
requiredRoles:ROLE[];
guardService:IGuardService;
forbidden?: () => React.ReactNode;
}
そしてそれぞれ ガード
コンポーネントを使用している。
export const Guard = (props: IGuardProps) => { もし(props.guardService.checkRole(props.requiredRoles))であれば
if (props.guardService.checkRole(props.requiredRoles)) { { (props.guardService.checkRole(props.requiredRoles))
return (
{props.children}を返します。
);
} else if (props.forbidden === undefined) { {.
return ;
} else {
return ()
{props.forbidden()}を返します。
);
}
}
使用例
export const AppHeader:FC = () => {
const guardService = new SimpleGuard();
const roleService = new RoleGuardService();
return (
<header>
<nav>
<ul>
<Guard<IRole> requiredRoles={[{name: "ADMIN"}]}guardService={roleService}>となります。
<li>管理者専用コンポーネント</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>とする。
<li>ユーザー専用コンポーネント</li>
</Guard>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
禁止={() => <div>禁止 - モデレーターのみ閲覧可</div>}>
<li>モデレーターコンポーネント</li>
</Guard>
<Guard<string> requiredRoles={["USER", "ADMIN"]} guardService={guardService}> ガードサービス。
<li>管理者とユーザーのコンポーネント</li>
</Guard>
<li>一般的な使用要素</li>
</ul>
</nav>
</header>
);
}
この例では IGuardservice
これは説明のためである。実際の使用例では
おそらく1つしか使わないだろう。
について ガード
をネストすることができる。ただ、アクセスはほとんどの外部インスタンスから順番に解決されることを覚えておいてほしい。
export const NestAppHeader:FC = () => {
const guardService = new SimpleGuard();
return (
<header>
<nav>
<ul>
<Guard<string> requiredRoles={["USER", "ADMIN"]} guardService={guardService}> ガードサービス。
<Guard<string> requiredRoles={["ADMIN"]}ガードサービス={guardService}>ガードサービス。
<li>管理者専用コンポーネント</li>
</Guard>
<Guard<string> requiredRoles={["USER"]} guardService={guardService}>とする。
<li>ユーザー専用コンポーネント</li>
</Guard>
<li>管理者とユーザーのコンポーネント</li>
<Guard<string> requiredRoles={["MODERATOR"]} guardService={guardService}
禁止={() => <div>禁止 - モデレーターのみ閲覧可</div>}>
<li>モデレーターコンポーネント</li>
</Guard>
</Guard>
<li>一般的な使用要素</li>
</ul>
</nav>
</header>
);
}
上記の例では モデレーターコンポーネント
なぜなら、ユーザーは1つの役割しか扱えないからである。最初に ガード
制限
役割 アドミン
そして ユーザー
だから モデレーター
がファーストチェックを通過することはない。
私たちは、いくつかのプロパティを非表示にする特殊なコンポーネントを構築することができます。
export const AdminGuard = (props: Omit) => { {.
return {
const guardService = new SimpleGuard();
return (
管理者専用コンポーネント
管理者専用コンポーネント
ユーザ専用コンポーネント
禁止 - モデレータのみ閲覧可
}>
モデレーターコンポーネント
ガード。
管理者とユーザーのコンポーネント
一般利用要素
);
}
```
この場合 アドミンガード
定義する アドミン
の役割を果たす。結果的に、私たちは 役割
タイプ
パラメータが必要だ。
この記事では、次のような方法を紹介する。 ガード
Reactのコンポーネント.私たちは、複雑なコードから始めます。
を読み、維持します。私たちはそれをより開発しやすい状態に進化させ、カスタム機能コンポーネントを導入します。次に
コンポーネントを拡張して機能を追加し、抽出サービスをリファクタリングし、最後にジェネリック型を追加する。
最終的に、テストと保守が容易なネスト可能なコンポーネントができた。