كيفية إضافة خاصية البحث المتقدم إلى تطبيقات React باستخدام مكتبة Fuse.js

دقائق القراءة: 7

تُعد خاصية البحث من الأدوات الأساسية التي تُمكن زوار موقعك من العثور على المحتوى الأكثر أهمية بالنسبة لهم بسهولة ويسر. ومع ذلك، غالبًا ما يكون تحديد القواعد والمنطق اللازم لتنفيذ هذه الخاصية تحديًا كبيرًا للمطورين. في هذا المقال، سنستكشف كيف يمكننا استخدام مكتبة Fuse.js القوية لإضافة وظيفة البحث إلى تطبيقاتنا المبنية باستخدام React، مما يوفر تجربة مستخدم محسّنة.

ما هي مكتبة Fuse.js؟

Fuse.js هي مكتبة JavaScript خفيفة الوزن ومرنة توفر إمكانيات بحث ضبابي (Fuzzy Search) لتطبيقات الويب. تتميز هذه المكتبة بسهولة الاستخدام الفائقة فور إخراجها من الصندوق، كما أنها توفر مجموعة واسعة من خيارات التكوين التي تسمح لك بضبط وتخصيص تجربة البحث لإنشاء حلول قوية ومناسبة لاحتياجاتك.

لماذا يُعد البحث مهمًا لتطبيقات الويب؟

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

ما الذي سنقوم ببنائه؟

سنبدأ بمثال بسيط لتطبيق Create React App. سيتضمن هذا التطبيق بعض المعلومات عن شخصيات من مسلسل Futurama المفضل لدي، منظمة كبيانات JSON مهيكلة ومعروضة في قائمة HTML بسيطة. باستخدام هذه القائمة، سنستخدم Fuse.js لتوفير إمكانيات البحث من جانب العميل (Client-Side Search)، مما يتيح لنا البحث عن الشخصية التي نبحث عنها بالاسم وتفاصيل أخرى.

الخطوة 0: تهيئة التطبيق الأساسي

للبدء، سنحتاج إلى محتوى للعمل عليه. لقد قمت بإنشاء قائمة بشخصيات من Futurama كبيانات JSON مهيكلة ووضعتها في قائمة ضمن تطبيق Create React App جديد.

تطبيق React للبحث عن شخصيات فيوتشوراما باستخدام Fuse.js

ستلاحظ أيضًا أنني أضفت بالفعل حقل إدخال للبحث. إنه ليس وظيفيًا بعد، لكننا سنستخدمه كنقطة بداية. إذا كنت ترغب في البدء من نفس النقطة، فقد أنشأت فرعًا في مستودع العرض الخاص بي يمكنك استنساخه محليًا لمتابعة المشروع معي:

git clone --single-branch --branch start git@github.com:colbyfayock/my-futurama-characters.git

هذا الأمر سيقوم باستنساخ الفرع المسمى start من المستودع. يمكنك أيضًا المتابعة مع التغييرات في هذا الالتزام (commit).

الخطوة 1: تثبيت مكتبة Fuse.js

أول شيء سنفعله هو إضافة Fuse.js إلى تطبيقنا. في مجلد مشروعك، قم بتشغيل الأمر التالي:

yarn add fuse.js
# أو
npm install --save fuse.js

سيؤدي هذا إلى حفظ المكتبة كاعتمادية في مشروعنا، مما يتيح لنا استخدامها. بعد ذلك، سنحتاج إلى استيراد المكتبة إلى تطبيقنا حتى نتمكن من البدء في البناء بها. في الجزء العلوي من ملفك، في حالتنا src/App.js إذا كنت تتابع معي في مشروع Create React App جديد، أضف السطر التالي:

import Fuse from 'fuse.js';

إذا أردت اختبار ما إذا كانت المكتبة تعمل بشكل صحيح، يمكنك استخدام console.log(Fuse) وسترى كائن Fuse الذي سنستخدمه لإنشاء إمكانيات البحث لدينا.

فحص كائن Fuse المستورد في وحدة التحكم

وبهذا، نكون جاهزين للبدء! يمكنك متابعة التغييرات في هذا الالتزام (commit).

الخطوة 2: إنشاء نسخة جديدة من محرك بحث Fuse

لاستخدام Fuse.js، سنحتاج أولاً إلى إنشاء نسخة جديدة منها. في الجزء العلوي من مكون React الخاص بك، أضف الكود التالي:

const fuse = new Fuse(characters, {
  keys: [
    'name',
    'company',
    'species'
  ]
});

ما يفعله هذا الكود هو:

  • إنشاء نسخة جديدة من Fuse.
  • تمرير مصفوفة characters التي تحتوي على كائنات البيانات الخاصة بنا.
  • تحديد المفاتيح (أو الحقول) الثلاثة في بياناتنا التي نرغب في البحث من خلالها، وهي 'name' و 'company' و 'species'.

بعد ذلك، لإجراء عملية البحث، يمكننا إضافة:

const results = fuse.search('bender');

وإذا قمنا بعرض results في وحدة التحكم (console)، يمكننا رؤية النتائج التالية:

نتائج البحث الأساسية باستخدام Fuse.js عن كلمة 'bender'

ستلاحظ أن لدينا نتائج أكثر من مجرد صديقنا Bender. توفر Fuse.js “بحثًا ضبابيًا” (fuzzy search)، مما يعني أنها تحاول مساعدتك في حال لم تكن متأكدًا مما تبحث عنه أو إذا كنت تخطئ في كتابة استعلامك. للحصول على فكرة عن كيفية عمل ذلك، دعنا نضيف خيار includeScore إلى عملية البحث لدينا:

const fuse = new Fuse(characters, {
  keys: [
    'name',
    'company',
    'species'
  ],
  includeScore: true
});

الآن يمكننا رؤية خاصية score في كائن النتائج لدينا.

نتائج بحث Fuse.js مع خاصية 'score' لتحديد دقة المطابقة

ستلاحظ أن النتيجة الأولى لديها درجة منخفضة جدًا. مع Fuse.js، تعني الدرجة المنخفضة أنها أقرب إلى تطابق تام. تشير الدرجة 0 إلى تطابق مثالي، بينما تشير الدرجة 1 إلى عدم تطابق كامل. هذا يعني أن النتيجة الأولى من المرجح جدًا أن تكون ما نبحث عنه، لكن المكتبة ليست واثقة من النتائج الأخرى.

لذا، مع نتائجنا، نريد ربطها بواجهة المستخدم (UI) الخاصة بنا. إذا لاحظت، فإن مخرجات المصفوفة تختلف عن ما نقوم بتعيينه لقائمة HTML، لذا دعنا ننشئ متغيرًا جديدًا يمكننا تغييره إلى:

const results = fuse.search('bender');
const characterResults = results.map(character => character.item);

ما يفعله هذا هو إنشاء مصفوفة جديدة باستخدام طريقة map التي ستتضمن فقط خاصية item من كل كائن في المصفوفة. ثم إذا استبدلنا characters.map داخل قائمتنا بـ characterResults.map:

<ul className="characters">
  {characterResults.map(character => {
    const { name, company, species, thumb } = character;
    // ... rest of your list item rendering
  })}
</ul>

يمكننا الآن أن نرى أن صفحتنا تعرض فقط النتائج الخاصة بـ "bender"!

واجهة المستخدم بعد تصفية النتائج لشخصية 'bender'

يمكنك متابعة التغييرات في هذا الالتزام (commit)!

الخطوة 3: إعداد البحث الديناميكي بناءً على إدخال المستخدم

الآن بعد أن أصبح لدينا بحث ثابت يعمل، نريد أن يتمكن المستخدم فعليًا من استخدام حقل الإدخال للبحث! لتحقيق ذلك، سنستخدم useState hook ونستمع إلى التغييرات في حقل الإدخال input، مما سيؤدي إلى إنشاء بحث ديناميكي لبياناتنا.

أولاً، قم باستيراد useState hook من React:

import React, { useState } from 'react';

بعد ذلك، دعنا نستخدم هذا hook لإنشاء نسخة حالة (state instance):

const [query, updateQuery] = useState('');

هنا، نقوم بإنشاء حالة جديدة تسمى query يمكننا تحديثها باستخدام updateQuery، والتي تُعيّن قيمة افتراضية لها وهي سلسلة نصية فارغة (''). بناءً على ذلك، دعنا نُخبر حقل إدخال البحث الخاص بنا باستخدام قيمة query كقيمته:

<input type="text" value={query} />

في هذه المرحلة، لا ينبغي أن يكون هناك أي اختلاف، حيث أننا نستخدم استعلامًا فارغًا.

شريط البحث فارغ في تطبيق React

الآن دعنا نضيف معالج أحداث (event handler) إلى حقل الإدخال الخاص بنا يمكننا استخدامه لتحديث حالتنا:

<input type="text" value={query} onChange={onSearch} />

وسنحتاج إلى إنشاء هذه الدالة حتى نتمكن من استخدامها:

function onSearch({ currentTarget }) {
  updateQuery(currentTarget.value);
}

سيؤدي هذا إلى تحديث query بقيمة الإدخال في أي وقت تتغير فيه. الآن بعد أن أصبح لدى query ما نريد البحث عنه، يمكننا تحديث نسخة البحث لدينا:

const results = fuse.search(query);

والآن إذا قمت بإعادة تحميل الصفحة، ستكون فارغة! لماذا؟

صفحة فارغة عند عدم وجود استعلام بحث في Fuse.js

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

نتائج البحث الديناميكية عن 'slurms' باستخدام Fuse.js

إذا أردنا إصلاح هذا بحيث تظهر جميع نتائجنا عندما لا يكون هناك استعلام، يمكننا القيام بذلك باستخدام عبارة if أو في مثالي، باستخدام عامل تشغيل ثلاثي (ternary operator)، والذي سيعرض جميع الشخصيات إذا لم يكن هناك استعلام:

const characterResults = query ? results.map(character => character.item) : characters;

عرض جميع الشخصيات عند عدم وجود استعلام بحث

وبهذا، أصبح لدينا بحثنا الأساسي يعمل!

نتائج البحث المفلترة عن 'zoidberg' في تطبيق React

يمكنك متابعة التغييرات في هذا الالتزام (commit)!

ما الذي يمكنني فعله بعد ذلك؟

ضبط إعدادات البحث

تأتي Fuse.js مع العديد من الخيارات التي يمكنك استخدامها لضبط بحثك بالطريقة التي تفضلها. هل تريد عرض النتائج الواثقة فقط؟ استخدم خيار threshold! هل تريد استعلامات حساسة لحالة الأحرف؟ استخدم خيار isCaseSensitive! يمكنك استكشاف جميع الخيارات المتاحة في توثيق Fuse.js الرسمي.

تعيين الاستعلام الافتراضي باستخدام معاملات URL

في بعض الأحيان، قد ترغب في تمكين المستخدمين من الارتباط بمجموعة معينة من النتائج مباشرةً. لتحقيق ذلك، يمكننا إضافة معامل URL جديد مثل ?q=bender. لجعل هذا يعمل، يمكنك الحصول على معامل URL هذا باستخدام JavaScript واستخدام قيمته لتعيين حالة query لدينا في React.

الخلاصة التقنية

تُقدم مكتبة Fuse.js حلاً أنيقًا وفعالًا لدمج خاصية البحث الضبابي في تطبيقات React. إن بساطة واجهة برمجتها (API) ومرونة خيارات التكوين تجعلها خيارًا ممتازًا للمطورين الذين يسعون لتحسين تجربة المستخدم من خلال البحث السريع والدقيق، حتى مع الأخطاء الإملائية المحتملة. القدرة على تحديد المفاتيح للبحث، وتضمين نقاط المطابقة (score)، وتطبيق البحث الديناميكي بسهولة باستخدام React Hooks، كلها عوامل تزيد من قوة هذه المكتبة. يمكن للمطورين استغلال هذه الميزات لإنشاء واجهات بحث متطورة تستجيب لاحتياجات المستخدمين وتوفر لهم وصولاً سهلاً إلى المحتوى، مما يعزز من قابلية استخدام التطبيق بشكل عام.

صورة دعائية للمؤلف كولبي فايوك

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *