نبذة تعريفية

رامى أحمد

الحمد لله الذي علَّم بالقلم، علَّم الإنسان ما لم يعلم، والصلاة والسلام على خير معلم الناس الخير سيدنا محمد - صلى الله عليه وسلم .. أما بعد ،،

اسمى رامى أحمد، بفضل الله - مؤسس منصة مرتكز

أسعى من خلال هذه المدونة المتواضعة إلى مشاركة خبرتى ومناقشة آرائي وأفكاري.

وفقنى الله وإياك إلى ما يحبه ويرضاه ،،

تابعنى على

التفاعلية في أبهي صورها مع useFetch

صورة المقال - التفاعلية في أبهي صورها مع useFetch

الحمد لله الذي علَّم بالقلم، علَّم الإنسان ما لم يعلم، والصلاة والسلام على خير معلِّم الناس الخير سيدنا محمد - صلَّى الله عليه وسلم … أما بعد ،،

في مقال سابق بعنوان "6 أسباب قد تدفعك لاختيار Nuxt لتنفيذ مشروعك القادم"، تناولت بإيجاز عملية "جلب البيانات"، وقلت أنها من الجوانب الثورية في Nuxt 3.

وفي هذا المقال، أتناول هذه العملية بمزيد من التفصيل مع مثال عملي بسيط يوضح جوانب قوتها وكيف تستفيد منها في تطبيقاتك بشكل فعّال.

الطريقة التقليدية بدون استخدام useFetch

في المثال التالي، نهدف إلى عرض بيانات مستخدمين من موقع Github، عن طريق جلب كل مستخدم بشكل فردي عند الضغط على زر "التالي" أو "السابق".

عند كل نقرة على هذه الأزرار، يتم إرسال طلب جديد لجلب البيانات الخاصة بالمستخدم التالي أو السابق، وبالتالي يتم تحديث بيانات المستخدم بشكل ديناميكي.

لمزيد من التوضيح، سنستخدم حالة تفاعلية باسم currentId لتخزين معرف المستخدم الحالي، وعند الرغبة في جلب بيانات مستخدم جديد، سواء كان المستخدم التالي أو السابق، نقوم بتحديث هذه الحالة عن طريق زيادتها أو تقليلها، مما يؤدي إلى إرسال طلب جديد إلى عنوان URL المحدد لهذا المعرف داخل الدالتين nextUser و previousUser.

وبمجرد استلام الاستجابة من الخادم، نقوم بتحديث currentUser التي تحتوي على اسم المستخدم وصورة ملفه الشخصي.

بناء علي هذا التحديث، يقوم Nuxt تلقائيًا بإعادة تحديث واجهة المستخدم لعرض البيانات الجديدة، مما يضمن تجربة سلسة وتفاعلية، بالإضافة إلى أنه عند تحميل الصفحة لأول مرة، نقوم مباشرةً بتنفيذ عملية الجلب الأولية حتى يتم عرض بيانات المستخدم الافتراضي فورًا دون الحاجة إلى أي تفاعل يدوي من المستخدم.

ولتطبيق ما سبق برمجيا يمكن أن يكون الكود بالشكل التالي:

<script setup lang="ts">
const currentId = ref(1); // Start with an initial user ID
const currentUser = ref();

// Function to fetch user data from GitHub API
const fetchUserForCurrentId = async () => {
  try {
    const user: { name: string | null; avatar_url: string } = await $fetch(
      `https://api.github.com/user/${currentId.value}`
    );
    currentUser.value = {
      name: user.name || 'No Name Provided',
      avatarUrl: user.avatar_url,
    };
  } catch (error) {
    console.error('Error fetching user:', error);
    currentUser.value = null;
  }
};

// Fetch user data when the component is mounted
onBeforeMount(() => {
  fetchUserForCurrentId();
});

// Function to fetch the next user (increment ID)
const nextUser = async () => {
  currentId.value++;
  await fetchUserForCurrentId();
};

// Function to fetch the previous user (decrement ID)
const previousUser = async () => {
  if (currentId.value > 1) {
    currentId.value--;
  }
  await fetchUserForCurrentId();
};
</script>

الطريقة السابقة تعمل بشكل جيد، لكنها ليست الطريقة الأمثل من حيث الاستفادة القصوي من إمكانيات Nuxt.

في الكود السابق، تم جلب البيانات بطريقة إجرائية (Imperative)، مما يعني أننا نحدد للبرنامج بشكل مباشر كل خطوة يجب تنفيذها، مثل تحديث المعرف، ثم إرسال الطلب، ثم انتظار الاستجابة، ثم تحديث البيانات يدويًا.

لكن Nuxt المبني علي Vue يوفر نظامًا تفاعليًا (Reactive) قويًا، يمكننا من خلاله جعل التطبيق يستجيب تلقائيًا لأي تغيير في الحالة، دون الحاجة إلى تشغيل العمليات يدويًا في كل مرة.

ما هي useFetch ؟

قبل أن نتمكن من استخدام useFetch بكفاءة، من المهم أولًا أن نفهم ما هي وكيف تعمل.

ببساطة، useFetch هي دالة قابلة لإعادة الاستخدام (Composable) توفرها Nuxt لتسهيل عملية جلب البيانات داخل المكونات.

للمزيد حول إعادة استخدام المنطق التفاعلي، يمكنك الرجوع إلى مقالي السابق "إعادة استخدام الكود بذكاء مع Composables في Nuxt"، حيث استعرضت أمثلة عملية وأفضل الممارسات لكتابة كود نظيف وقابل للصيانة.

في Nuxt تشير كلمة Composable إلى دالة تستفيد من Composition API لاحتواء منطق معين يمكن إعادة استخدامه بسهولة في أكثر من مكون، مما يساعد في تنظيم الكود وجعله أكثر مرونة.

ما يميز useFetch هو أنه يحتفظ بحالة تفاعلية داخليًا، ويتابع أي تغييرات تحدث على المتغيرات التي يعتمد عليها، وعندما يتم تغيير هذه القيم، يقوم تلقائيًا بإعادة تنفيذ عملية الجلب دون الحاجة إلى تشغيلها يدويًا.

هذا يعني أن useFetch يتكامل بشكل كامل مع دورة حياة المكون، مما يجعل إدارة البيانات أكثر سهولة وسلاسة، ويقلل من كمية الكود المطلوب لكتابة عمليات الجلب التقليدية.

ولمزيد من التوضيح، يمكن استدعاء useFetch مع إعدادات مخصصة لطلب HTTP، مثل عنوان URL، والمعاملات (Query Parameters)، والترويسات (Headers)، وهيئة الطلب (Body)، وطريقة الطلب (Method)، وغيرها.

بحيث يمكن تحديد هذه القيم إما كمتغيرات عادية أو كمتغيرات تفاعلية مثل ref وreactive وcomputed.

وعند استخدام متغير تفاعلي في الإعدادات، فإن أي تغيير يطرأ عليه يؤدي إلى إعادة تنفيذ الطلب تلقائيًا بواسطة useFetch، مما يجعله متكاملًا مع النظام التفاعلي في Nuxt.

تُعيد useFetch كائنًا يحتوي على ثلاث قيم رئيسية:

  • البيانات data: تمثل البيانات المسترجعة من الاستجابة.
  • الحالة pending: متغير منطقي (boolean) يشير إلى ما إذا كان الطلب قيد التنفيذ.
  • الخطأ error: كائن يحتوي على معلومات حول أي خطأ قد يحدث أثناء الطلب.

بالإضافة إلى ذلك، يمكننا استخدام خيار pick ضمن إعدادات useFetch، والذي يتيح لنا تحديد المفاتيح التي نرغب في استخراجها من البيانات المسترجعة، مع تجاهل باقي القيم غير المطلوبة.

لمزيد من التفاصيل حول إعدادات useFetch وإمكانياته، يمكن الرجوع إلى توثيق Nuxt الرسمي.

تطبيق useFetch علي المثال السابق

بدلًا من استدعاء دالة جلب البيانات يدويًا في كل مرة نرغب في عرض المستخدم التالي أو السابق، يمكننا جعل العملية أكثر تفاعلية وسلاسة باستخدام useFetch.

كل ما نحتاج إليه هو تحديث قيمة currentId، وسيقوم useFetch تلقائيًا بجلب بيانات المستخدم الجديد دون الحاجة إلى تشغيل أي دالة إضافية.

لكي يعمل useFetch بشكل تلقائي عند تغيير معرف المستخدم (currentId)، نحتاج إلى جعل عنوان URL نفسه متغيرًا تفاعليًا.

يمكننا تحقيق ذلك باستخدام computed، وهي دالة تتيح لنا إنشاء متغير تفاعلي محسوب، يتم تحديث قيمته تلقائيًا بمجرد حدوث أي تغيير في المتغيرات التي يعتمد عليها.

لتحسين أداء تطبيقاتك وجعلها أكثر مرونة، يمكنك الرجوع إلى مقالي السابق "فهم التفاعلية في Vue لجعل تطبيقاتك أكثر سلاسة"، حيث قدمت شرحًا عمليًا حول إدارة البيانات التفاعلية بكفاءة وأفضل الممارسات لتعزيز استجابة التطبيق وتحسين تجربة المستخدم.

عند استخدام computed لإنشاء عنوان URL ديناميكي يعتمد على currentId، سيقوم useFetch بإعادة تنفيذ الطلب تلقائيًا كلما تغير معرف المستخدم، مما يجعل الكود أكثر بساطة وكفاءة، ويوفر تجربة أكثر سلاسة للمستخدم.

<script setup lang="ts">
const currentId = ref(1);
const url = computed(() => `https://api.github.com/user/${currentId.value}`);
const { data: currentUser } = useFetch<{
  name: string | null;
  avatar_url: string;
}>(url, { pick: ['name', 'avatar_url'] });

const nextUser = async () => {
  currentId.value++;
};

const previousUser = async () => {
  if (currentId.value > 1) {
    currentId.value--;
  }
};
</script>

لاحظ في الكود السابق تم تمرير عنوان URL إلى useFetch وإضافة خيار pick لتحديد البيانات المطلوبة من الاستجابة، كما ذكرنا سابقًا.

وأيضا لم نعد بحاجة إلى استخدام onBeforeMount، لأن useFetch يقوم تلقائيًا بجلب البيانات عند تحميل المكون، مما يجعل الكود أكثر بساطة وتنظيمًا دون الحاجة إلى تنفيذ الطلب يدويًا.

وهذا هو المطلوب!

الشيء الوحيد الذي نحتاج إلى تغييره يدويًا هو تحديث قيمة currentId عند التنقل بين المستخدمين، إذ بمجرد تغيير هذه القيمة، يقوم useFetch تلقائيًا بإعادة جلب البيانات وتحديث الواجهة دون الحاجة لأي تدخل إضافي، مما يجعل التطبيق أكثر كفاءة وسلاسة.

ختاما، يسعدني معرفة آرائك ومقترحاتك حول المقال، فهي تسهم في تحسين وتطوير ما أقدمه من محتوى، لذا فضلا اترك تعليقك، وسأكون سعيداً بقراءة مقترحاتك والعمل على تقديم محتوى يلبي تطلعاتك - بإذن الله.

وفقنى الله وإياك إلى ما يحبه ويرضاه ،،