35 KiB
بناء تطبيق مصرفي الجزء 4: مفاهيم إدارة الحالة
اختبار ما قبل المحاضرة
المقدمة
إدارة الحالة تشبه نظام الملاحة في مركبة الفضاء فوياجر – عندما تسير الأمور بسلاسة، بالكاد تلاحظ وجودها. ولكن عندما تسوء الأمور، تصبح الفرق بين الوصول إلى الفضاء بين النجوم أو الانجراف في الفراغ الكوني. في تطوير الويب، تمثل الحالة كل ما يحتاجه تطبيقك لتذكره: حالة تسجيل دخول المستخدم، بيانات النماذج، تاريخ التنقل، وحالات الواجهة المؤقتة.
مع تطور تطبيقك المصرفي من نموذج تسجيل دخول بسيط إلى تطبيق أكثر تعقيدًا، ربما واجهت بعض التحديات الشائعة. عند تحديث الصفحة، يتم تسجيل خروج المستخدمين بشكل غير متوقع. عند إغلاق المتصفح، تختفي كل التقدم. عند تصحيح مشكلة، تجد نفسك تبحث في وظائف متعددة تعدل نفس البيانات بطرق مختلفة.
هذه ليست علامات على البرمجة السيئة – إنها آلام النمو الطبيعية التي تحدث عندما تصل التطبيقات إلى مستوى معين من التعقيد. يواجه كل مطور هذه التحديات عندما تنتقل تطبيقاته من "إثبات المفهوم" إلى "جاهز للإنتاج".
في هذه الدرس، سنقوم بتنفيذ نظام إدارة حالة مركزي يحول تطبيقك المصرفي إلى تطبيق موثوق واحترافي. ستتعلم كيفية إدارة تدفقات البيانات بشكل متوقع، الحفاظ على جلسات المستخدم بشكل مناسب، وخلق تجربة مستخدم سلسة تتطلبها تطبيقات الويب الحديثة.
المتطلبات الأساسية
قبل الغوص في مفاهيم إدارة الحالة، ستحتاج إلى إعداد بيئة التطوير الخاصة بك بشكل صحيح ووضع أساس تطبيقك المصرفي. يعتمد هذا الدرس مباشرة على المفاهيم والكود من الأجزاء السابقة من هذه السلسلة.
تأكد من توفر المكونات التالية قبل المتابعة:
الإعداد المطلوب:
- أكمل درس جلب البيانات - يجب أن يقوم تطبيقك بتحميل وعرض بيانات الحساب بنجاح
- قم بتثبيت Node.js على نظامك لتشغيل واجهة برمجة التطبيقات الخلفية
- قم بتشغيل واجهة برمجة التطبيقات للخادم محليًا لمعالجة عمليات بيانات الحساب
اختبار بيئتك:
تحقق من تشغيل خادم واجهة برمجة التطبيقات بشكل صحيح عن طريق تنفيذ هذا الأمر في نافذة الأوامر:
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
ما الذي يفعله هذا الأمر:
- يرسل طلب GET إلى خادم واجهة برمجة التطبيقات المحلي
- يختبر الاتصال ويتحقق من استجابة الخادم
- يعرض معلومات إصدار واجهة برمجة التطبيقات إذا كان كل شيء يعمل بشكل صحيح
تشخيص مشاكل الحالة الحالية
مثل شيرلوك هولمز الذي يفحص مسرح الجريمة، نحتاج إلى فهم ما يحدث بالضبط في تنفيذنا الحالي قبل أن نتمكن من حل لغز جلسات المستخدم المفقودة.
لنقم بإجراء تجربة بسيطة تكشف عن تحديات إدارة الحالة الأساسية:
🧪 جرب هذا الاختبار التشخيصي:
- قم بتسجيل الدخول إلى تطبيقك المصرفي وانتقل إلى لوحة التحكم
- قم بتحديث صفحة المتصفح
- لاحظ ما يحدث لحالة تسجيل الدخول الخاصة بك
إذا تمت إعادة توجيهك إلى شاشة تسجيل الدخول، فقد اكتشفت مشكلة كلاسيكية في استمرارية الحالة. يحدث هذا السلوك لأن تنفيذنا الحالي يخزن بيانات المستخدم في متغيرات JavaScript التي يتم إعادة تعيينها مع كل تحميل للصفحة.
مشاكل التنفيذ الحالية:
المتغير البسيط account من الدرس السابق يخلق ثلاث مشاكل كبيرة تؤثر على تجربة المستخدم وصيانة الكود:
| المشكلة | السبب الفني | تأثير المستخدم |
|---|---|---|
| فقدان الجلسة | تحديث الصفحة يمسح متغيرات JavaScript | يجب على المستخدمين إعادة المصادقة بشكل متكرر |
| تحديثات متفرقة | وظائف متعددة تعدل الحالة مباشرة | يصبح التصحيح أكثر صعوبة |
| تنظيف غير مكتمل | تسجيل الخروج لا يمسح جميع مراجع الحالة | مخاوف محتملة تتعلق بالأمان والخصوصية |
التحدي المعماري:
مثل تصميم تيتانيك المقسم الذي بدا قويًا حتى غمرت المياه عدة أقسام في وقت واحد، فإن إصلاح هذه المشاكل بشكل فردي لن يعالج المشكلة المعمارية الأساسية. نحن بحاجة إلى حل شامل لإدارة الحالة.
💡 ما الذي نحاول تحقيقه هنا؟
إدارة الحالة تتعلق بحل لغزين أساسيين:
- أين بياناتي؟: تتبع المعلومات التي لدينا ومن أين تأتي
- هل الجميع على نفس الصفحة؟: التأكد من أن ما يراه المستخدمون يتطابق مع ما يحدث فعليًا
خطة العمل لدينا:
بدلاً من مطاردة المشاكل، سنقوم بإنشاء نظام إدارة حالة مركزي. فكر فيه كوجود شخص منظم للغاية مسؤول عن كل الأمور المهمة:
فهم تدفق البيانات هذا:
- يركز جميع حالات التطبيق في مكان واحد
- يوجه جميع تغييرات الحالة من خلال وظائف محكومة
- يضمن تزامن واجهة المستخدم مع الحالة الحالية
- يوفر نمطًا واضحًا وقابلًا للتنبؤ لإدارة البيانات
💡 رؤية احترافية: يركز هذا الدرس على المفاهيم الأساسية. بالنسبة للتطبيقات المعقدة، توفر مكتبات مثل Redux ميزات إدارة حالة أكثر تقدمًا. فهم هذه المبادئ الأساسية سيساعدك على إتقان أي مكتبة لإدارة الحالة.
⚠️ موضوع متقدم: لن نغطي التحديثات التلقائية لواجهة المستخدم التي يتم تشغيلها بواسطة تغييرات الحالة، حيث يتضمن ذلك مفاهيم البرمجة التفاعلية. اعتبر هذا خطوة ممتازة تالية في رحلة تعلمك!
المهمة: هيكلة الحالة المركزية
لنبدأ بتحويل إدارة الحالة المتفرقة إلى نظام مركزي. هذه الخطوة الأولى تؤسس الأساس لجميع التحسينات التي تليها.
الخطوة 1: إنشاء كائن حالة مركزي
استبدل إعلان account البسيط:
let account = null;
بكائن حالة منظم:
let state = {
account: null
};
لماذا هذا التغيير مهم:
- يركز جميع بيانات التطبيق في مكان واحد
- يجهز الهيكل لإضافة المزيد من خصائص الحالة لاحقًا
- يخلق حدودًا واضحة بين الحالة والمتغيرات الأخرى
- يؤسس نمطًا يتوسع مع نمو تطبيقك
الخطوة 2: تحديث أنماط الوصول إلى الحالة
قم بتحديث وظائفك لاستخدام الهيكل الجديد للحالة:
في وظائف register() و login()، استبدل:
account = ...
بـ:
state.account = ...
في وظيفة updateDashboard()، أضف هذا السطر في الأعلى:
const account = state.account;
ما الذي تحققه هذه التحديثات:
- يحافظ على الوظائف الحالية مع تحسين الهيكل
- يجهز الكود لإدارة حالة أكثر تطورًا
- يخلق أنماطًا متسقة للوصول إلى بيانات الحالة
- يؤسس الأساس لتحديثات الحالة المركزية
💡 ملاحظة: هذا التغيير لا يحل مشاكلنا فورًا، لكنه يخلق الأساس الضروري للتحسينات القوية القادمة!
تنفيذ تحديثات الحالة المحكومة
مع تركيز حالتنا، الخطوة التالية تتضمن إنشاء آليات محكومة لتعديلات البيانات. هذا النهج يضمن تغييرات حالة متوقعة وتصحيحًا أسهل.
المبدأ الأساسي يشبه التحكم في حركة الطيران: بدلاً من السماح للوظائف المتعددة بتعديل الحالة بشكل مستقل، سنوجه جميع التغييرات من خلال وظيفة واحدة محكومة. يوفر هذا النمط إشرافًا واضحًا على متى وكيف تحدث تغييرات البيانات.
إدارة الحالة غير القابلة للتغيير:
سنعامل كائن state الخاص بنا ككائن غير قابل للتغيير، مما يعني أننا لن نعدله مباشرة. بدلاً من ذلك، كل تغيير ينشئ كائن حالة جديدًا مع البيانات المحدثة.
على الرغم من أن هذا النهج قد يبدو غير فعال مقارنة بالتعديلات المباشرة، إلا أنه يوفر فوائد كبيرة للتصحيح، الاختبار، والحفاظ على توقعات التطبيق.
فوائد إدارة الحالة غير القابلة للتغيير:
| الفائدة | الوصف | التأثير |
|---|---|---|
| التوقعية | تحدث التغييرات فقط من خلال وظائف محكومة | أسهل للتصحيح والاختبار |
| تتبع التاريخ | كل تغيير حالة ينشئ كائنًا جديدًا | يتيح وظيفة التراجع/الإعادة |
| منع الآثار الجانبية | لا تعديلات عرضية | يمنع الأخطاء الغامضة |
| تحسين الأداء | سهل اكتشاف متى تغيرت الحالة فعليًا | يتيح تحديثات واجهة مستخدم فعالة |
عدم القابلية للتغيير في JavaScript باستخدام Object.freeze():
يوفر JavaScript Object.freeze() لمنع تعديلات الكائن:
const immutableState = Object.freeze({ account: userData });
// Any attempt to modify immutableState will throw an error
تفصيل ما يحدث هنا:
- يمنع تعيين الخصائص أو حذفها مباشرة
- يرمي استثناءات إذا تم محاولة التعديل
- يضمن أن تغييرات الحالة يجب أن تمر عبر وظائف محكومة
- يخلق عقدًا واضحًا لكيفية تحديث الحالة
💡 استكشاف عميق: تعرف على الفرق بين الكائنات غير القابلة للتغيير السطحية و العميقة في وثائق MDN. فهم هذا التمييز ضروري للهياكل المعقدة للحالة.
المهمة
لنقم بإنشاء وظيفة جديدة updateState():
function updateState(property, newData) {
state = Object.freeze({
...state,
[property]: newData
});
}
في هذه الوظيفة، نقوم بإنشاء كائن حالة جديد وننسخ البيانات من الحالة السابقة باستخدام عامل الانتشار (...). ثم نقوم بتجاوز خاصية معينة من كائن الحالة بالبيانات الجديدة باستخدام ترميز الأقواس [property] للتعيين. وأخيرًا، نقوم بتجميد الكائن لمنع التعديلات باستخدام Object.freeze(). لدينا فقط خاصية account مخزنة في الحالة حاليًا، ولكن مع هذا النهج يمكنك إضافة العديد من الخصائص كما تحتاج في الحالة.
سنقوم أيضًا بتحديث تهيئة state للتأكد من أن الحالة الأولية مجمدة أيضًا:
let state = Object.freeze({
account: null
});
بعد ذلك، قم بتحديث وظيفة register عن طريق استبدال تعيين state.account = result; بـ:
updateState('account', result);
قم بنفس الشيء مع وظيفة login، استبدل state.account = data; بـ:
updateState('account', data);
سنستغل الفرصة الآن لإصلاح مشكلة عدم مسح بيانات الحساب عندما ينقر المستخدم على تسجيل الخروج.
قم بإنشاء وظيفة جديدة logout():
function logout() {
updateState('account', null);
navigate('/login');
}
في updateDashboard()، استبدل إعادة التوجيه return navigate('/login'); بـ return logout();
جرب تسجيل حساب جديد، تسجيل الخروج ثم تسجيل الدخول مرة أخرى للتحقق من أن كل شيء لا يزال يعمل بشكل صحيح.
نصيحة: يمكنك الاطلاع على جميع تغييرات الحالة عن طريق إضافة
console.log(state)في أسفلupdateState()وفتح وحدة التحكم في أدوات تطوير المتصفح.
تنفيذ استمرارية البيانات
تتطلب مشكلة فقدان الجلسة التي حددناها سابقًا حلًا للاستمرارية يحافظ على حالة المستخدم عبر جلسات المتصفح. هذا يحول تطبيقنا من تجربة مؤقتة إلى أداة موثوقة واحترافية.
فكر في كيفية احتفاظ الساعات الذرية بالوقت الدقيق حتى أثناء انقطاع التيار الكهربائي عن طريق تخزين الحالة الحرجة في ذاكرة غير متطايرة. وبالمثل، تحتاج تطبيقات الويب إلى آليات تخزين مستمرة للحفاظ على بيانات المستخدم الأساسية عبر جلسات المتصفح وتحديثات الصفحة.
أسئلة استراتيجية لاستمرارية البيانات:
قبل تنفيذ الاستمرارية، فكر في هذه العوامل الحرجة:
| السؤال | سياق التطبيق المصرفي | تأثير القرار |
|---|---|---|
| هل البيانات حساسة؟ | رصيد الحساب، تاريخ المعاملات | اختر طرق تخزين آمنة |
| كم يجب أن تستمر؟ | حالة تسجيل الدخول مقابل تفضيلات واجهة المستخدم المؤقتة | اختر مدة التخزين المناسبة |
| هل يحتاجها الخادم؟ | رموز المصادقة مقابل إعدادات واجهة المستخدم | حدد متطلبات المشاركة |
خيارات تخزين المتصفح:
توفر المتصفحات الحديثة عدة آليات تخزين، كل منها مصمم لحالات استخدام مختلفة:
واجهات برمجة التطبيقات الأساسية للتخزين:
-
localStorage: تخزين المفتاح/القيمة المستمر- يستمر البيانات عبر جلسات المتصفح إلى أجل غير مسمى
- يبقى بعد إعادة تشغيل المتصفح وإعادة تشغيل الكمبيوتر
- محدد لنطاق موقع الويب المحدد
- مثالي لتفضيلات المستخدم وحالات تسجيل الدخول
-
sessionStorage: تخزين الجلسة المؤقت- يعمل بشكل مشابه لـ localStorage أثناء الجلسات النشطة
- يمسح تلقائيًا عند إغلاق علامة تبويب المتصفح
- مثالي للبيانات المؤقتة التي لا يجب أن تستمر
-
كوكيز HTTP: تخزين مشترك مع الخادم
- يتم إرسالها تلقائيًا مع كل طلب للخادم
- مثالي لـ رموز المصادقة
- محدودة الحجم ويمكن أن تؤثر على الأداء
متطلبات تسلسل البيانات:
كل من localStorage و sessionStorage يخزن فقط سلاسل النصوص:
// Convert objects to JSON strings for storage
const accountData = { user: 'john', balance: 150 };
localStorage.setItem('account', JSON.stringify(accountData));
// Parse JSON strings back to objects when retrieving
const savedAccount = JSON.parse(localStorage.getItem('account'));
فهم التسلسل:
- يحول كائنات JavaScript إلى سلاسل JSON باستخدام
JSON.stringify() - يعيد بناء الكائنات من JSON باستخدام
JSON.parse() - يتعامل تلقائيًا مع الكائنات والمصفوفات المتداخلة المعقدة
- يفشل مع الوظائف، القيم غير المعرفة، والمرجع الدائري
💡 خيار متقدم: بالنسبة للتطبيقات المعقدة التي تعمل دون اتصال مع مجموعات بيانات كبيرة، يمكن النظر في استخدام
IndexedDBAPI. يوفر قاعدة بيانات كاملة على جانب العميل ولكنه يتطلب تنفيذًا أكثر تعقيدًا.
المهمة: تنفيذ تخزين دائم باستخدام localStorage
سنقوم بتنفيذ تخزين دائم بحيث يبقى المستخدمون مسجلين الدخول حتى يقوموا بتسجيل الخروج بشكل صريح. سنستخدم localStorage لتخزين بيانات الحساب عبر جلسات المتصفح.
الخطوة 1: تعريف إعدادات التخزين
const storageKey = 'savedAccount';
ما الذي يوفره هذا الثابت:
- إنشاء معرف ثابت لبياناتنا المخزنة
- منع الأخطاء الإملائية في مراجع مفاتيح التخزين
- تسهيل تغيير مفتاح التخزين إذا لزم الأمر
- اتباع أفضل الممارسات لكتابة كود قابل للصيانة
الخطوة 2: إضافة التخزين التلقائي
أضف هذا السطر في نهاية وظيفة updateState():
localStorage.setItem(storageKey, JSON.stringify(state.account));
تفصيل ما يحدث هنا:
- تحويل كائن الحساب إلى سلسلة JSON للتخزين
- حفظ البيانات باستخدام مفتاح التخزين الثابت
- تنفيذ تلقائيًا عند حدوث تغييرات في الحالة
- ضمان أن البيانات المخزنة متزامنة دائمًا مع الحالة الحالية
💡 فائدة معمارية: لأننا قمنا بتجميع جميع تحديثات الحالة من خلال
updateState()، فإن إضافة التخزين استغرق سطرًا واحدًا فقط من الكود. هذا يوضح قوة القرارات المعمارية الجيدة!
الخطوة 3: استعادة الحالة عند تحميل التطبيق
قم بإنشاء وظيفة تهيئة لاستعادة البيانات المحفوظة:
function init() {
const savedAccount = localStorage.getItem(storageKey);
if (savedAccount) {
updateState('account', JSON.parse(savedAccount));
}
// Our previous initialization code
window.onpopstate = () => updateRoute();
updateRoute();
}
init();
فهم عملية التهيئة:
- استرجاع أي بيانات حساب محفوظة مسبقًا من localStorage
- تحليل سلسلة JSON مرة أخرى إلى كائن JavaScript
- تحديث الحالة باستخدام وظيفة التحديث المُدارة
- استعادة جلسة المستخدم تلقائيًا عند تحميل الصفحة
- تنفيذ قبل تحديث المسارات لضمان توفر الحالة
الخطوة 4: تحسين المسار الافتراضي
قم بتحديث المسار الافتراضي للاستفادة من التخزين الدائم:
في updateRoute()، استبدل:
// Replace: return navigate('/login');
return navigate('/dashboard');
لماذا هذا التغيير منطقي:
- الاستفادة من نظام التخزين الجديد بشكل فعال
- السماح للوحة التحكم بمعالجة فحوصات المصادقة
- إعادة التوجيه إلى تسجيل الدخول تلقائيًا إذا لم تكن هناك جلسة محفوظة
- إنشاء تجربة مستخدم أكثر سلاسة
اختبار التنفيذ الخاص بك:
- قم بتسجيل الدخول إلى تطبيقك البنكي
- قم بتحديث صفحة المتصفح
- تحقق من أنك ما زلت مسجل الدخول وعلى لوحة التحكم
- أغلق وأعد فتح المتصفح
- عد إلى تطبيقك وتأكد من أنك ما زلت مسجل الدخول
🎉 إنجاز محقق: لقد قمت بتنفيذ إدارة حالة دائمة بنجاح! الآن يتصرف تطبيقك مثل تطبيق ويب احترافي.
تحقيق التوازن بين التخزين الدائم وحداثة البيانات
نظام التخزين الدائم الخاص بنا يحافظ بنجاح على جلسات المستخدم، ولكنه يقدم تحديًا جديدًا: قدم البيانات. عندما يقوم مستخدمون أو تطبيقات متعددة بتعديل نفس بيانات الخادم، تصبح المعلومات المخزنة محليًا قديمة.
يشبه هذا الوضع الملاحين الفايكنغ الذين اعتمدوا على كل من خرائط النجوم المخزنة والملاحظات السماوية الحالية. توفر الخرائط الاتساق، لكن الملاحين يحتاجون إلى ملاحظات جديدة لمواكبة الظروف المتغيرة. وبالمثل، يحتاج تطبيقنا إلى حالة مستخدم دائمة وبيانات خادم حديثة.
🧪 اكتشاف مشكلة حداثة البيانات:
- قم بتسجيل الدخول إلى لوحة التحكم باستخدام حساب
test - قم بتشغيل هذا الأمر في الطرفية لمحاكاة معاملة من مصدر آخر:
curl --request POST \
--header "Content-Type: application/json" \
--data "{ \"date\": \"2020-07-24\", \"object\": \"Bought book\", \"amount\": -20 }" \
http://localhost:5000/api/accounts/test/transactions
- قم بتحديث صفحة لوحة التحكم في المتصفح
- لاحظ ما إذا كنت ترى المعاملة الجديدة
ما الذي يظهره هذا الاختبار:
- يوضح كيف يمكن أن يصبح التخزين المحلي "قديمًا" (غير محدث)
- يحاكي سيناريوهات واقعية حيث تحدث تغييرات البيانات خارج تطبيقك
- يكشف التوتر بين التخزين الدائم وحداثة البيانات
تحدي حداثة البيانات:
| المشكلة | السبب | تأثير المستخدم |
|---|---|---|
| البيانات القديمة | لا تنتهي صلاحية localStorage تلقائيًا | يرى المستخدمون معلومات غير محدثة |
| تغييرات الخادم | تطبيقات/مستخدمون آخرون يعدلون نفس البيانات | وجهات نظر غير متسقة عبر المنصات |
| التخزين المؤقت مقابل الواقع | التخزين المحلي لا يتطابق مع حالة الخادم | تجربة مستخدم سيئة وارتباك |
استراتيجية الحل:
سنقوم بتنفيذ نمط "التحديث عند التحميل" الذي يوازن بين فوائد التخزين الدائم والحاجة إلى البيانات الحديثة. يحافظ هذا النهج على تجربة المستخدم السلسة مع ضمان دقة البيانات.
المهمة: تنفيذ نظام تحديث البيانات
سنقوم بإنشاء نظام يقوم تلقائيًا بجلب بيانات جديدة من الخادم مع الحفاظ على فوائد إدارة الحالة الدائمة.
الخطوة 1: إنشاء محدّث بيانات الحساب
async function updateAccountData() {
const account = state.account;
if (!account) {
return logout();
}
const data = await getAccount(account.user);
if (data.error) {
return logout();
}
updateState('account', data);
}
فهم منطق هذه الوظيفة:
- التحقق مما إذا كان المستخدم مسجل الدخول حاليًا (state.account موجود)
- إعادة التوجيه إلى تسجيل الخروج إذا لم يتم العثور على جلسة صالحة
- جلب بيانات حساب جديدة من الخادم باستخدام وظيفة
getAccount()الحالية - التعامل مع أخطاء الخادم بشكل جيد عن طريق تسجيل الخروج من الجلسات غير الصالحة
- تحديث الحالة بالبيانات الجديدة باستخدام نظام التحديث المُدار
- تشغيل التخزين الدائم تلقائيًا من خلال وظيفة
updateState()
الخطوة 2: إنشاء معالج تحديث لوحة التحكم
async function refresh() {
await updateAccountData();
updateDashboard();
}
ما الذي تحققه وظيفة التحديث هذه:
- تنسيق عملية تحديث البيانات وتحديث واجهة المستخدم
- انتظار تحميل البيانات الجديدة قبل تحديث العرض
- ضمان أن تعرض لوحة التحكم المعلومات الأكثر حداثة
- الحفاظ على فصل نظيف بين إدارة البيانات وتحديث واجهة المستخدم
الخطوة 3: التكامل مع نظام المسارات
قم بتحديث تكوين المسار لتشغيل التحديث تلقائيًا:
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard', init: refresh }
};
كيف يعمل هذا التكامل:
- تنفيذ وظيفة التحديث في كل مرة يتم فيها تحميل مسار لوحة التحكم
- ضمان عرض البيانات الجديدة دائمًا عند تنقل المستخدمين إلى لوحة التحكم
- الحفاظ على هيكل المسار الحالي مع إضافة حداثة البيانات
- توفير نمط ثابت لتهيئة المسارات الخاصة
اختبار نظام تحديث البيانات الخاص بك:
- قم بتسجيل الدخول إلى تطبيقك البنكي
- قم بتشغيل أمر curl السابق لإنشاء معاملة جديدة
- قم بتحديث صفحة لوحة التحكم أو التنقل بعيدًا ثم العودة
- تحقق من ظهور المعاملة الجديدة فورًا
🎉 توازن مثالي محقق: يجمع تطبيقك الآن بين تجربة المستخدم السلسة ودقة بيانات الخادم الحديثة!
تحدي GitHub Copilot Agent 🚀
استخدم وضع Agent لإكمال التحدي التالي:
الوصف: قم بتنفيذ نظام إدارة حالة شامل مع وظيفة التراجع/الإعادة لتطبيق البنك. سيساعدك هذا التحدي على ممارسة مفاهيم إدارة الحالة المتقدمة بما في ذلك تتبع تاريخ الحالة، التحديثات غير القابلة للتغيير، ومزامنة واجهة المستخدم.
المهمة: قم بإنشاء نظام إدارة حالة محسّن يتضمن: 1) مصفوفة تاريخ الحالة التي تتبع جميع الحالات السابقة، 2) وظائف التراجع والإعادة التي يمكنها العودة إلى الحالات السابقة، 3) أزرار واجهة المستخدم لعمليات التراجع/الإعادة على لوحة التحكم، 4) حد أقصى لتاريخ الحالة يبلغ 10 حالات لمنع مشاكل الذاكرة، و5) تنظيف مناسب للتاريخ عند تسجيل خروج المستخدم. تأكد من أن وظيفة التراجع/الإعادة تعمل مع تغييرات رصيد الحساب وتستمر عبر تحديثات المتصفح.
تعرف على المزيد حول وضع Agent هنا.
🚀 تحدي: تحسين التخزين
يتم الآن التعامل مع جلسات المستخدم، تحديث البيانات، وإدارة الحالة بشكل فعال في تنفيذك. ومع ذلك، فكر فيما إذا كان نهجنا الحالي يوازن بشكل مثالي بين كفاءة التخزين والوظائف.
مثل أساتذة الشطرنج الذين يميزون بين القطع الأساسية والبيادق القابلة للتضحية، تتطلب إدارة الحالة الفعالة تحديد البيانات التي يجب أن تستمر مقابل تلك التي يجب أن تكون دائمًا حديثة من الخادم.
تحليل التحسين:
قم بتقييم تنفيذ localStorage الحالي الخاص بك وفكر في هذه الأسئلة الاستراتيجية:
- ما هي المعلومات الدنيا المطلوبة للحفاظ على مصادقة المستخدم؟
- ما هي البيانات التي تتغير بشكل متكرر بحيث يوفر التخزين المحلي فائدة قليلة؟
- كيف يمكن أن يحسن تحسين التخزين الأداء دون التأثير على تجربة المستخدم؟
هذا النوع من التحليل المعماري يميز المطورين ذوي الخبرة الذين يأخذون في الاعتبار كل من الوظائف والكفاءة في حلولهم.
استراتيجية التنفيذ:
- تحديد البيانات الأساسية التي يجب أن تستمر (على الأرجح فقط تعريف المستخدم)
- تعديل تنفيذ localStorage لتخزين بيانات الجلسة الأساسية فقط
- ضمان تحميل البيانات الحديثة دائمًا من الخادم عند زيارات لوحة التحكم
- اختبار أن النهج المحسن يحافظ على نفس تجربة المستخدم
اعتبار متقدم:
- مقارنة التوازن بين تخزين بيانات الحساب الكاملة مقابل مجرد رموز المصادقة
- توثيق قراراتك وأسبابها لأعضاء الفريق في المستقبل
سيساعدك هذا التحدي على التفكير كمطور محترف يأخذ في الاعتبار كل من تجربة المستخدم وكفاءة التطبيق. خذ وقتك لتجربة طرق مختلفة!
اختبار ما بعد المحاضرة
الواجب
تنفيذ مربع حوار "إضافة معاملة"
إليك مثال على النتيجة بعد إكمال الواجب:
إخلاء المسؤولية:
تم ترجمة هذا المستند باستخدام خدمة الترجمة بالذكاء الاصطناعي Co-op Translator. بينما نسعى لتحقيق الدقة، يرجى العلم أن الترجمات الآلية قد تحتوي على أخطاء أو عدم دقة. يجب اعتبار المستند الأصلي بلغته الأصلية المصدر الموثوق. للحصول على معلومات حاسمة، يُوصى بالترجمة البشرية الاحترافية. نحن غير مسؤولين عن أي سوء فهم أو تفسيرات خاطئة تنشأ عن استخدام هذه الترجمة.

