الحفاظ على جلسة المستخدم المسجل دخوله في React: دليل شامل
مقدمة: لماذا نحتاج إلى الحفاظ على تسجيل دخول المستخدم في React؟
عند البحث عن كيفية الحفاظ على تسجيل دخول المستخدم في تطبيقات React، قد لا تجد الكثير من النتائج المباشرة أو الأمثلة الواضحة التي تشرح كيفية تحقيق ذلك بسهولة. تهدف هذه المقالة إلى تقديم دليل مبسط وشامل يوضح لك الخطوات الدقيقة لتنفيذ هذه الميزة الأساسية في تطبيقات الويب الحديثة.
ربما تكون قد صادفت مصطلح localStorage أثناء بحثك عن حلول لهذه المشكلة. نعم، سنستخدم localStorage كآلية لتخزين بيانات المستخدم، وسأوضح لك بالضبط كيفية تطبيقه بفعالية.
فهم localStorage: قاعدة بيانات المتصفح
قبل الغوص في التفاصيل البرمجية، دعنا نفهم ما هو localStorage وخصائصه الرئيسية:
localStorageهو جزء من واجهة برمجة تطبيقات تخزين الويب (Web Storage API) التي توفرها المتصفحات. يمكن اعتباره قاعدة بيانات بسيطة خاصة بالمتصفح.- تُخزن البيانات داخل متصفحك في ذاكرة جهاز الكمبيوتر الخاص بك بشكل دائم (حتى يقوم المستخدم بمسحها يدويًا أو عبر إعدادات المتصفح).
- يتميز
localStorageبكونه خاصًا بالمصدر (origin-specific)؛ بمعنى آخر، لا يمكن لموقع ويب واحد الوصول إلى بياناتlocalStorageالخاصة بموقع ويب آخر. هذا يضمن مستوى من الأمان والخصوصية للبيانات المخزنة.
الإعداد الأولي لتطبيق React
لنبدأ بتهيئة بيئة العمل الخاصة بنا. لقد قمت بنشر خادم Express بسيط على Heroku لاستخدامه في اختبار هذا التطبيق. يمكنك إنشاء تطبيق React جديد باستخدام Create React App أو أي أداة بناء تفضلها. بعد ذلك، توجه إلى مكون <App /> الرئيسي.
سنحتاج إلى مكتبة axios لإجراء طلبات HTTP إلى الخادم. قم بتثبيتها باستخدام الأمر التالي:
npm install axios
بعد التثبيت، قم باستيرادها داخل ملف App.js الخاص بك. الآن، لنقم بإنشاء نموذج تسجيل دخول بسيط يقبل اسم مستخدم وكلمة مرور:
import React, { useState } from "react";
import axios from "axios";
const App = () => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [user, setUser] = useState();
const handleSubmit = async e => {
// سيتم تعريف هذه الدالة لاحقًا
};
// إذا كان هناك مستخدم مسجل دخوله، اعرض رسالة الترحيب
if (user) {
return <div>{user.name} is logged in</div>;
}
// إذا لم يكن هناك مستخدم، اعرض نموذج تسجيل الدخول
return (
<form onSubmit={handleSubmit}>
<label htmlFor="username">Username:</label>
<input
type="text"
value={username}
placeholder="enter a username"
onChange={({ target }) => setUsername(target.value)}
/>
<div>
<label htmlFor="password">Password:</label>
<input
type="password"
value={password}
placeholder="enter a password"
onChange={({ target }) => setPassword(target.value)}
/>
</div>
<button type="submit">Login</button>
</form>
);
};
export default App;
كما ترى في الكود أعلاه، قمنا بتعريف دوال الحالة (useState) لاسم المستخدم وكلمة المرور وحالة المستخدم. كما قمنا بتعريف دالة غير متزامنة handleSubmit لمعالجة طلب تسجيل الدخول (سنقوم بتفصيلها لاحقًا). الأهم من ذلك، قمنا بتعريف شرط يعرض رسالة “{user.name} is logged in” إذا كان هناك كائن user في الحالة، وإلا فإنه يعرض نموذج تسجيل الدخول.
معالجة حدث تسجيل الدخول (handleSubmit)
الآن لنكمل دالة handleSubmit التي ستكون مسؤولة عن إرسال بيانات تسجيل الدخول إلى الخادم وتخزين استجابة المستخدم. ستعمل هذه الدالة وفقًا للخطوات التالية:
- منع السلوك الافتراضي للنموذج (
e.preventDefault()). - جمع اسم المستخدم وكلمة المرور من الحالة.
- إرسال تفاصيل تسجيل الدخول إلى الخادم باستخدام
axios.post. - إذا كان الطلب ناجحًا، قم بتخزين معلومات المستخدم المستلمة في
localStorage. - تحديث حالة المستخدم (
user state) فيReact.
const handleSubmit = async e => {
e.preventDefault();
const user = { username, password };
try {
// إرسال اسم المستخدم وكلمة المرور إلى الخادم
const response = await axios.post(
"http://blogservice.herokuapp.com/api/login",
user
);
// تعيين حالة المستخدم في React
setUser(response.data);
// تخزين المستخدم في localStorage (يجب تحويل الكائن إلى سلسلة JSON)
localStorage.setItem('user', JSON.stringify(response.data));
console.log(response.data);
} catch (error) {
console.error("Login failed:", error);
// يمكنك هنا عرض رسالة خطأ للمستخدم
}
};
ملاحظة هامة: لقد أضفت كتلة try/catch لمعالجة الأخطاء في الدوال غير المتزامنة (async functions)، وهو أمر بالغ الأهمية لتطبيقات العالم الحقيقي. كما قمت بتعديل localStorage.setItem لتحويل الكائن response.data إلى سلسلة JSON باستخدام JSON.stringify() قبل التخزين، لأن localStorage يخزن السلاسل النصية فقط.
الآن بعد أن انتهينا من الدالة، يمكنك تشغيل npm start لاختبار تطبيقك. قم بتسجيل الدخول باستخدام اسم المستخدم: user2 وكلمة المرور: password. يجب أن تتلقى استجابة مشابهة لما يلي، والتي تتضمن userId و token و username:

التحقق من تسجيل دخول المستخدم عند تحميل التطبيق (useEffect)
الخطوة التالية هي التأكد من أن المستخدم يظل مسجل الدخول حتى بعد تحديث الصفحة أو إغلاق المتصفح وإعادة فتحه. للقيام بذلك، نحتاج إلى طريقة للتحقق مما إذا كان هناك مستخدم مسجل دخوله مسبقًا في كل مرة يتم فيها تحميل مكون <App />. لهذا الغرض، نستخدم خطاف useEffect:
useEffect(() => {
const loggedInUser = localStorage.getItem("user");
if (loggedInUser) {
const foundUser = JSON.parse(loggedInUser);
setUser(foundUser);
}
}, []); // مصفوفة تبعية فارغة لضمان التشغيل مرة واحدة عند التحميل الأولي
تذكر استخدام مصفوفة تبعية فارغة ([]) في خطاف useEffect الخاص بك. هذا يضمن أن الدالة داخل useEffect سيتم تشغيلها مرة واحدة فقط عند تحميل المكون لأول مرة، مما يجعلها مثالية للتحقق من وجود مستخدم مسجل دخوله عند بدء تشغيل التطبيق.
الآن يجب أن يعمل تطبيقنا بشكل مثالي. سنحصل على الصفحة أدناه بعد أن يقوم المستخدم بتسجيل الدخول لأول مرة ويتم تخزين تفاصيله في localStorage. إذا قمت بتحديث الصفحة، ستلاحظ أن المستخدم يظل مسجل الدخول وتستمر صفحة الترحيب في الظهور، مما يوفر تجربة مستخدم سلسة.

تنفيذ وظيفة تسجيل الخروج (Logout)
كخطوة إضافية وميزة ضرورية، دعنا نوضح كيفية تنفيذ وظيفة تسجيل الخروج. لتسجيل الخروج، نقوم ببساطة بتفريغ حالة المستخدم (user state) وإزالة بيانات المستخدم من localStorage.
إنشاء زر تسجيل الخروج
أولاً، سنضيف زر تسجيل خروج إلى واجهة المستخدم عندما يكون المستخدم مسجل الدخول. يمكنك وضعه داخل الشرط الذي يعرض رسالة الترحيب:
<div>
{user.name} is logged in
<button onClick={handleLogout}>Logout</button>
</div>
إنشاء دالة تسجيل الخروج (handleLogout)
ثم، ننشئ دالة handleLogout التي ستقوم بتنظيف الحالة المحلية و localStorage:
const handleLogout = () => {
setUser(null); // أو setUser({})، حسب كيفية تعريفك للحالة الأولية للمستخدم غير المسجل دخوله
setUsername("");
setPassword("");
localStorage.clear(); // إزالة جميع البيانات من localStorage للمصدر الحالي
// يمكنك أيضًا استخدام localStorage.removeItem('user'); لإزالة مفتاح معين فقط
};
لقد قمت بتغيير setUser({}) إلى setUser(null) ليكون أكثر وضوحًا بأن المستخدم غير موجود. كما أضفت تعليقًا حول استخدام localStorage.removeItem('user') كبديل لـ localStorage.clear() إذا كنت ترغب في إزالة مفتاح معين فقط بدلاً من مسح كل شيء.
وبهذا نكون قد انتهينا من تنفيذ نظام تسجيل دخول مستمر ووظيفة تسجيل الخروج في تطبيق React الخاص بك!
الخلاصة التقنية
يُعد الحفاظ على جلسة المستخدم المسجل دخوله في تطبيقات React باستخدام localStorage حلاً فعالاً وسهل التنفيذ لتحسين تجربة المستخدم بشكل كبير. من خلال تخزين رمز المستخدم أو بياناته الأساسية (غير الحساسة) في localStorage، يمكن للتطبيق تذكر حالة المستخدم حتى بعد تحديث الصفحة أو إغلاق المتصفح، مما يقلل من الحاجة إلى إعادة تسجيل الدخول المتكررة.
ومع ذلك، من المهم ملاحظة أن localStorage ليس آمنًا بما يكفي لتخزين البيانات الحساسة مثل رموز الوصول (access tokens) أو معلومات المستخدم الشخصية التي تتطلب حماية عالية، لأنه عرضة لهجمات XSS (Cross-Site Scripting). في مثل هذه الحالات، يُفضل استخدام حلول أكثر أمانًا مثل HTTP-only cookies أو إدارة الجلسات من جانب الخادم. يظل localStorage خيارًا ممتازًا لتخزين تفضيلات المستخدم، أو حالة واجهة المستخدم، أو بيانات غير حساسة تهدف إلى تحسين سرعة التطبيق وتجربة المستخدم.