إيجابيات وسلبيات React
لماذا يستحق استخدام React؟ ما هي مزايا مكتبة JavaScript هذه؟ لمعرفة الإجابات تعمق في هذه المقالة واكتشف الفوائد الحقيقية لاستخدام React.
تعرّف على كيفية تبسيط وتحسين رؤية المكونات في React باستخدام التصيير الشرطي ومكونات الحماية.
أود اليوم مناقشة كيفية التحكم في رؤية المكونات في React. لكن قبل أن نبدأ هناك
إخلاء مسؤولية:
الحل المقدم ليس آمناً جداً بمعنى حماية تطبيقك من "المخترقين" (أياً كانوا).
تذكر أنك بحاجة إلى حماية نقاط النهاية الخاصة بك واستخدام الممارسات الجيدة في تصميم التطبيق. هذا الحل فقط
يجعل عملك أسهل قليلاً.
إحدى الوظائف الأكثر شيوعًا هي إظهار المكون فقط لمجموعة من المستخدمين الذين لديهم بعض الحقوق المحددة,
الأدوار أو الامتيازات. الحل الشائع هو إضافة بعض إذا
ق إلى الكودوالتحقق من الشروط يدويًا وإظهار العناصر أو عدم إظهارها.
دعنا نلقي نظرة على SimpleAppHeader
مكون يحتوي على عدد قليل من عناصر التنقل.
<!-- wp:paragraph -->
<p><code>نوع المخطوطة jsx<br>>
تصدير const const SimpleAppHeader: FC = () => {<br>>
إرجاع (<br> (<br>
<br>>
<nav><br>>
<ul><br> <ul><br>
{<br> <<br>
دور المستخدم الحالي === "ADMIN" و<<br>>
<<li> <li> مكون المسؤول فقط</li><br>
}<br><br>
{<br> <<br>
الدور الحاليUser.role === "USER" &&&<br><br>
<<li> مكون المستخدم فقط</li><br>
}<br><br>
{<br> <<br>
(currentUser.role === "ADMIN" ||||دور المستخدم الحالي === "USER") و<<<br> <<br>
<<li> مكون المسؤول والمستخدم فقط</li><br>
<<br><br>
<li> عنصر الاستخدام العام</li><li><br>
</ul><br> </ul><br>
</nav><br> </nav><br>
<br> <br>
) <<br>>
>><br>
</code></p>
<!-- /wp:paragraph -->
تبدو "ليست سيئة". ربما يمكنك تغليف عمليات التحقق في دوال لتقليل التعقيد. المستخدم الحالي
كائن ما
الذي يحتوي على الدور
خاصية، ولكن يمكن أن تكون أي شيء نرغب في استخدامه كموضوع لآلية التحكم الخاصة بنا.
يحتوي هذا الرمز على بعض المشاكل. إذا كان المشروع ينمو ربما نستخدم هذا التركيب في العديد من الأماكن. لذلك نحن بحاجة إلى النسخ,
بطريقة أو بأخرى، الظروف يصعب الحفاظ على هذا الرمز وتغييره في المستقبل. خاصة عندما تتغير قواعد الوصول أثناء
الوقت على سبيل المثال نحتاج إلى تغيير المستخدم الحالي
إلى شيء آخر. من الصعب جدًا اختباره. تحتاج إلى كتابة العديد من الاختبارات
فقط للتحقق مما إذا كانت حالتك على ما يرام
حان الوقت لتبسيط هذا الرمز قليلاً. يمكننا استخراج بعض الطرق وجعل الشيفرة أقصر وأقل تعقيدًا:
const isAdmin = (الدور: سلسلة): منطقية => الدور === "ADMIN";
const isUser = (الدور: سلسلة): منطقية => الدور === "USER";
const isAdminOrUser = (الدور: سلسلة): منطقية => isAdmin(الدور) || isUser(الدور);
تصدير const const SimplifiedAppHeader: FC = () => { {
إرجاع (
{
هو مشرف(currentUser.role) &&
مكون المسؤول فقط
}
{
isUser(currentUser.role) &&&
مكون المستخدم فقط
}
{
(هوAdminOrUser(currentUser.role)) &&
مكون المسؤول والمستخدم فقط
}
عنصر الاستخدام العام
)
}
```
تبدو واعدة. نحد من الضوضاء od تكرار الأسطر. الكود أكثر قابلية للقراءة وأسهل في الصيانة. لكن ألقِ نظرة على
الوظيفة هو مشرف أو مستخدم
. لدينا دوران فقط. إذا قدمنا دورًا ثالثًا نحتاج إلى إنشاء مجموعة أخرى من الدوال
يجمع بين الأدوار حان الوقت لنسخة أخرى.
دعونا نقدم الدالة له دور
التي ستكون بديلاً لـ إيزكس
الوظائف.
const hasRole = (الدور: سلسلة، الدور المطلوب: سلسلة[]): منطقية => {
دع الموجود: سلسلة | | غير محدد = requiredRole.find(s => الدور === s);
إرجاع الموجود != = = غير معرّف;
}
تصدير const const FilteringAppHeader: FC = () => { {
إرجاع (
{
له دور(currentUser.role, ["ADMIN"]) &&
مكون المسؤول فقط
}
{
haveRole(currentUser.role, ["USER"]) &&
مكون المستخدم فقط
}
{
hasRole(currentUser.role, ["ADMIN", "USER"]) &&&
مكون المسؤول والمستخدم فقط
}
عنصر الاستخدام العام
)
}
```
يبدو جيدًا الآن. لا يزال لدينا شروط في جزء html من الشيفرة، ولكن يمكننا الآن اختبار له دور
الوظيفة والثقة في أنها
مع مجموعة صحيحة من المعلمات. أصبحت إضافة الأدوار أو تغييرها أسهل الآن. نستخدم مصفوفة تحتوي على جميع
الأدوار التي نحتاجها في مكانها.
ومع ذلك، فإن هذا الحل مرتبط بـ المستخدم الحالي
كائن. الافتراض هو أن الكائن عالمي أو سهل الوصول إليه بطريقة ما في
أي مكان في التطبيق. لذا يمكننا محاولة تغليف ذلك. بالطبع، يمكننا نقله إلى له دور
الوظيفة:
const hasRole = (الدور المطلوب: سلسلة []): منطقية => {
دع الموجود: سلسلة | غير معرّف = requiredRole.find(s => s => currentUser.role === s);
إرجاع الموجود != = = غير محدد;
}
ولكن هذا لا يعطينا شيئاً تقريباً.
الحراسة
المكوّنحان الوقت لإنشاء مكون يغلف المنطق بأكمله. أسميته الحراسة
وهذه هي الطريقة التي أريد استخدامها بها.
تصدير const const GuardedAppHeader: FC = () => { {
إرجاع (
</ترويسة
);
}
يحتاج المكون إلى خاصيتين. الأولى الأطفال
مسؤول عن المحتوى الخاضع للحراسة. ثانياً الأدوار المطلوبة
أن
التعامل مع مجموعة من الأدوار التي تتيح لنا الوصول
نحتاج إلى تمثيل هذه البنية. الأمر بسيط للغاية. نقوم بتوسيع النوع React.PropsWithChildren
الذي يحتوي على الأطفال
الخاصية. بالطبع يمكنك إضافة هذه الخاصية يدويًا إلى نوعك وحذف الامتداد.
واجهة IGuardProps امتداد React.PropsWithChildren {
الأدوار المطلوبة: سلسلة[];
}
المكوّن نفسه بسيط أيضاً. سنعيد استخدام له دور
الوظيفة هنا.
تصدير const const Guard = (الدعائم: IGuardProps) => {
const hasRole = (الدور المطلوب: سلسلة []): منطقية => { {
دع الموجود: سلسلة | غير معرّف = requiredRole.find(s => s => currentUser.role === s);
إرجاع الموجود != = = غير محدد;
}
إذا كان (لديه دور(props.requiredRoles)) { {
إرجاع (
{props.children}
);
) } آخر {
العودة ;
}
}
"`
ويمكنني أن أقول توقف هنا، ولكن سيكون الأمر سهلاً للغاية. الآن لدينا مكون، ويمكننا استخدامه إلى أقصى حد 😀
ستكون الخطوة الأولى هي إضفاء الطابع الخارجي على الشيكات. المستخدم الحالي
قيمة مشفرة بشكل ثابت. أرغب في تغليف هذه القيمة
إلى بعض الخدمات، التي "ستعرف" كيفية التحقق من الأدوار. هذا يعني تقنياً أننا ننقل له دور
دالة إلى أخرى
الفصل.
أنشئ واجهة بسيطة خدمة IGuardService
التي لها خاصية واحدة فقط - له دور
.
تصدير واجهة IGuardService {
checkRole: (الأدوار: سلسلة []) => منطقية;
}
الآن يمكن أن يبدو التنفيذ البسيط كالتالي
فئة SimpleGuard تنفذ IGuardService {
التحقق من الدور(الأدوار: سلسلة[]): منطقية {
دع الموجود: سلسلة | | غير معرّف = أدوار.find(e => e === currentUser.role);
إرجاع الموجود != = = غير محدد;
}
}
لاستخدامها نحتاج إلى تغيير خصائص IGuardProperaries
وحالة الاستخدام.
تصدير واجهة IGuardProps واجهة IGuardProps تمتد React.PropsWithChildren {
الأدوار المطلوبة: سلسلة[];
guardService: IGuardService;
}
// ...
const AppHeader: FC = () => { {
const guardService = جديد SimpleGuard();
إرجاع (
مكون المسؤول فقط
مكون المستخدم فقط
مكون المسؤول والمستخدم فقط
عنصر الاستخدام العام
);
}
```
يبدو المكون الآن مثل:
تصدير const const Guard = (الخاصيات: IGuardProps) => {
إذا (إذا (props.guardService.checkRole(props.requiredRoles)) {
إرجاع (
{props.children}
);
) } آخر {
العودة ;
}
}
أفضل بكثير. خدمة الحراسة
تفصلنا عن المنطق الذي يتحقق من الأدوار. يمكننا تغييره دون عواقب على
المكوّن. حالة الاستخدام الشائعة هي استخدام الوهمي في الاختبارات وبعض التنفيذ "الحقيقي" في شيفرة الإنتاج.
سيكون التحسين التالي هو التعامل مع العرف ممنوع
العنصر. الحل الحالي يجعل العنصر فارغًا. نحتاج أولاً إلى
التغيير IGuardProps
إضافة الدالة التي ستُصيّر ذلك العنصر.
تصدير واجهة IGuardProps واجهة IGuardProps ممتدة React.PropsWithChildren {
الأدوار المطلوبة: سلسلة[];
guardService: IGuardService;
ممنوع؟: () => React.ReactNode;
}
هذه خاصية اختيارية، ينتهي الاسم بحرف علامة الاستفهام. لذا يمكن أن تكون دالة أو غير محدد
. نحتاج إلى
التعامل معها في الحراسة
المكوّن.
تصدير const const Guard = (الدعائم: IGuardProps) => {
إذا (إذا (props.guardService.checkRole(props.requiredRoles)) {
إرجاع (
{props.children}
);
) } آخر إذا (props.forbidden === غير محدد) {
إرجاع ;
} أخرى { {
إرجاع ( (
{props.forbidden()}
);
}
}
// ...
تصدير const AppHeader: FC = () => { {
const guardService = جديد SimpleGuard();
إرجاع (
مكون المسؤول فقط
مكون المستخدم فقط
ممنوع - يمكن للمشرف فقط رؤية هذا المكون
}>
مكون المنسق
مكون المشرف والمستخدم
عنصر الاستخدام العام
);
}
```
حان وقت التغيير الكبير الأخير. يدعم مكوّن الإصدار الحالي الأدوار فقط كـ السلسلة
. يمكن أن يكون لدينا العديد من
أنواع الخصائص التي نود التحقق منها. الأرقام أو الأنواع المخصصة ليست شيئًا مميزًا. سأضيف دعم الأنواع العامة.
الخطوة الأولى هي التغييرات في خدمة IGuardService
الواجهة. ستعتمد التطبيقات على نوع القيمة المختبرة. يمكن أن
يكون أي شيء، لذا يجب على الواجهة التعامل معه.
تصدير واجهة IGuardService {
checkRole: (الأدوار: ROLE[]) => منطقية;
}
الآن يأخذ مجموعة من الدور
نوع عام. سيتغير تطبيقنا البسيط قليلاً.
فئة SimpleGuard تنفذ IGuardService {
التحقق من الدور(الأدوار: سلسلة[]): منطقية {
دع الموجود: سلسلة | | غير معرّف = أدوار.find(e => e === دور المستخدم الحالي);
إرجاع الموجود != = = غير محدد;
}
}
نحن بحاجة إلى إضافة متغير النوع، ولكن يمكننا إعداد تنفيذ يدعم القطب المتحرك
الواجهة.
واجهة IRole {
الاسم: سلسلة;
}
//...
تقوم فئة RoleGuardService بتنفيذ IGuardService {
التحقق من الدور(الأدوار: IRole[]): منطقية {
دع العثور: IRole | غير محدد = أدوار.find(e => e === userWithRole.role);
إرجاع موجود != = = غير محدد;
}
}
```
الخطوة الثانية هي نشر هذا التغيير إلى IGuardProps
.
<الواجهة IGuardProps واجهة IGuardProps امتداد React.PropsWithChildren {
الأدوار المطلوبة: ROLE[];
guardService: IGuardService;
ممنوع؟: () => React.ReactNode;
}
وعلى التوالي إلى الحراسة
المكوّن.
تصدير const const Guard = (props: IGuardProps) => {
إذا (إذا (props.guardService.checkRole(props.requiredRoles)) {
إرجاع (
{props.children}
);
) } آخر إذا (props.forbidden === غير محدد) {
إرجاع ;
} أخرى { {
إرجاع ( (
{props.forbidden()}
);
}
}
وحالات الاستخدام لدينا
تصدير const AppHeader: FC = () => { {
const guardService = جديد SimpleGuard();
const roleService = جديد RoleGuardService();
إرجاع (
<header>
<nav>
<ul>
<Guard<IRole>الأدوار المطلوبة={{{{{الاسم: "ADMIN"}]} GuardService={{roleService}}>
<li>المكون الإداري فقط</li>
</Guard>
<Guard<strinز>الأدوار المطلوبة={{{{"USER"]} GuardService={guardService}>
<li>مكون المستخدم فقط</li>
</Guard>
<Guard<strinز>الأدوار المطلوبة={{{{"MODERATOR"]} guardService={guardService}
ممنوع={() => <div>ممنوع - يمكن للمشرف فقط رؤية ذلك</div>}>
<li>مكون المنسق</li>
</Guard>
<Guard<strinز>الأدوار المطلوبة={{{{"USER"، "ADMIN"]} guardService={guardService}>
<li>مكون المسؤول والمستخدم</li>
</Guard>
<li>عنصر الاستخدام العام</li>
</ul>
</nav>
</header>
);
}
في هذا المثال أستخدم في هذا المثال تطبيق كل من IGuardservice
لأغراض توضيحية فقط. في حالات الاستخدام الحقيقي أنت
ربما تستخدم واحدة فقط.
إن الحراسة
يمكن أن تكون متداخلة. فقط تذكر أنه سيتم حل الوصول بالترتيب من معظم المثيل الخارجي.
تصدير const const NestAppHeader: FC = () => { {
const guardService = جديد SimpleGuard();
إرجاع (
<header>
<nav>
<ul>
<Guard<strinز>الأدوار المطلوبة={{{{"USER"، "ADMIN"]} guardService={guardService}>
<Guard<strinز>الأدوار المطلوبة={{{{"ADMIN"]} GuardService={guardService}>
<li>المكون الإداري فقط</li>
</Guard>
<Guard<strinز>الأدوار المطلوبة={{{{"USER"]} GuardService={guardService}>
<li>مكون المستخدم فقط</li>
</Guard>
<li>مكون المسؤول والمستخدم</li>
<Guard<strinز>الأدوار المطلوبة={{{{"MODERATOR"]} guardService={guardService}
ممنوع={() => <div>ممنوع - يمكن للمشرف فقط رؤية ذلك</div>}>
<li>مكون المنسق</li>
</Guard>
</Guard>
<li>عنصر الاستخدام العام</li>
</ul>
</nav>
</header>
);
}
في المثال أعلاه مكون المنسق
لا يمكن أن تظهر أبدًا، لأن المستخدم يمكنه التعامل مع دور واحد فقط. أولاً الحراسة
الحدود
الأدوار إلى الإدارة
و المستخدم
لذا، فإن مدير المناقشة
لن يجتاز الفحص الأول
يمكننا بناء مكونات متخصصة تخفي بعض الخصائص.
تصدير const const AdminGuard = (الخاصيات: حذف <) => {
إرجاع <>
{props.children}
}
//...
تصدير const constizedAppHeader: FC = () => { {
const guardService = جديد SimpleGuard();
إرجاع (
مكون المسؤول فقط
>
مكون المستخدم فقط
ممنوع - يمكن للمشرف فقط رؤية ذلك
}>
مكون المنسق
>
مكون المشرف والمستخدم
عنصر الاستخدام العام
);
}
```
في هذه الحالة الحارس الإداري
التعريف المسبق الإدارة
الدور. في العواقب، نحتاج إلى تعريف واضح لنوع الدور
النوع
المعلمة.
في هذه المقالة سأوضح لك كيفية إنشاء واستخدام الحراسة
المكوّن في React. نبدأ من التعليمات البرمجية المعقدة التي يصعب
قراءتها وصيانتها. نطوره إلى حالة أكثر ملاءمة للمطورين ونقدم مكونًا وظيفيًا مخصصًا. بعد ذلك نقوم
توسيع المكوّن بإضافة وظائف إضافية، وإعادة هيكلة خدمة الاستخراج، وأخيرًا إضافة أنواع عامة.
أخيرًا، لدينا مكون يمكن أن يكون متداخلًا يسهل اختباره وصيانته.