جستجوی پیشرفته React با هوک useSearch

با رشد پیچیدگی پروژه‌های React، نیاز به یک سیستم جستجوی پیشرفته، قدرتمند و منعطف بیش از پیش احساس می‌شود. جستجو در رابط‌های کاربری، تنها به فیلتر کردن ساده داده‌ها محدود نیست؛ بلکه باید بتواند در مواجهه با داده‌های حجیم، ساختارهای تودرتو و حتی اشتباهات تایپی کاربران نیز عملکرد مؤثری داشته باشد.

در این مقاله، یک راهکار جامع برای پیاده‌سازی سیستم جستجو در React مورد بررسی قرار می‌گیرد. تمرکز اصلی، طراحی یک هوک قابل استفاده مجدد به نام useSearch است که قابلیت‌هایی مانند پشتیبانی از جستجوی فازی (Fuzzy Search)، بهینه‌سازی عملکرد با تکنیک‌های مختلف و مدیریت داده‌های بزرگ با استفاده از Pagination را فراهم می‌کند.

این مقاله برای چه کسانی مناسب است؟

این مقاله برای توسعه‌دهندگان React در سطوح مختلف طراحی شده است؛ چه افراد تازه‌کار که به دنبال ارتقاء قابلیت‌های پروژه‌های خود هستند و چه برنامه‌نویسان حرفه‌ای که با محدودیت‌های رایج در جستجو پیشرفته React مواجه‌اند، از جمله کندی در پردازش داده‌های حجیم، ضعف در تشخیص تایپ اشتباه یا دشواری در مدیریت ساختارهای پیچیده داده.
هدف این مقاله، ارائه یک سیستم جستجوی پیشرفته React است که هم قابل اعتماد باشد و هم به‌راحتی در پروژه‌های واقعی قابل استفاده و توسعه‌پذیر باقی بماند.

آنچه در این مقاله خواهیم آموخت:

در پایان این مقاله، با مفاهیم و مهارت‌های زیر آشنا خواهیم شد:

  • شناسایی چالش‌های رایج در پیاده‌سازی جستجوی ساده
  • ساخت یک هوک جستجوی قدرتمند با پشتیبانی از داده‌های تودرتو
  • بهینه‌سازی عملکرد جستجو با استفاده از Debounce و Memoization
  • ارتقاء تجربه کاربری از طریق جستجوی فازی و تحمل خطا
  • مدیریت حجم بالای نتایج با استفاده از تکنیک Pagination

چالش‌ها و مشکلات در پیاده‌سازی جستجوی ساده در React 

کار خود را با ساخت یک کامپوننت جستجوی ابتدایی شروع می‌کنیم:

function SimpleSearch() {
    const data = [
        { name: "JavaScript" },
        { name: "Python" },
        { name: "Java" }
    ];

    const [query, setQuery] = useState("");

    const results = data.filter((item) => item.name.includes(query));

    return (
        <div>
            <input
                type="text"
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                placeholder="Search..."
            />
            <ul>
                {results.map((item, index) => (
                    <li key={index}>{item.name}</li>
                ))}
            </ul>
        </div>
    );
}

در نگاه اول، به‌نظر می‌رسد که این پیاده‌سازی به‌خوبی کار می‌کند: یک کوئری وارد کرده و نتایج مرتبط را دریافت می‌کنیم. اما در اپلیکیشن‌های واقعی، جستجو باید فراتر از مقایسه ساده رشته‌ها باشد. در ادامه، به برخی از محدودیت‌های اصلی این روش اشاره می‌کنیم:

  • پشتیبانی محدود از داده‌ها: این روش فقط برای رشته‌های ساده کار می‌کند و برای ساختارهای داده‌ی پیچیده کاربردی نیست.
  • عدم پشتیبانی از آبجکت‌های تودرتو: اگر داده‌های ما شامل ساختارهای عمیق‌تر باشند (مثلاً { user: { name: "JavaScript" } }) این روش جواب نمی‌دهد.
  • عدم تحمل اشتباه تایپی: کوچک‌ترین اشتباه در تایپ مثل "javascrpt" باعث می‌شود "JavaScript" پیدا نشود، که برای کاربر آزاردهنده است.
  • کاهش عملکرد: با هر فشردن کلید، کل لیست مجدداً رندر می‌شود، که در داده‌های بزرگ منجر به لگ و کندی خواهد شد.

واضح است که به چیزی قدرتمندتر نیاز داریم. در ادامه قصد داریم سیستمی بسازیم که هم انعطاف‌پذیر باشد، هم بهینه و هم کاربرپسند.

روش ساخت هوک قابل استفاده مجدد useSearch برای جستجوی پیشرفته در React

برای حل این مشکلات، هوکی طراحی می‌کنیم که:

  • از انواع مختلف داده (رشته، عدد، تاریخ، و آبجکت‌های تودرتو) پشتیبانی کند.
  • با استفاده از تکنیک‌هایی مثل debounce و memoization عملکرد را بهبود دهد.
  • از جستجوی فازی برای مدیریت اشتباه‌های تایپی استفاده کند.

چگونه باید این هوک را بسازیم؟

ابتدا هوک را تعریف می‌کنیم. این هوک داده‌ها، کوئری جستجو و لیستی از توابع فیلترکننده را دریافت می‌کند:

// hooks/useSearch.js

function useSearch(data, query, ...filters) {
    const debouncedQuery = useDebounce(query, 300);

    return React.useMemo(() => {
        const dataArray = Array.isArray(data) ? data : [data];

        try {
            // Apply each filter function in sequence
            return filters.reduce(
                (acc, feature) => feature(acc, debouncedQuery),
                dataArray
            );
        } catch (error) {
            console.error("Error applying search features:", error);
            return dataArray;
        }
    }, [data, debouncedQuery, filters]);
}

مدیریت کوئری جستجو با useDebounce در پروژه‌های React

بدون استفاده از debounce، هر بار که کاربر کلیدی را فشار می‌دهد، یک جستجوی جدید آغاز می‌شود. تصور کنید می‌خواهیم واژه‌ی "apple" را تایپ کنیم؛ با هر حرف (a، p، p، l، e) یک درخواست جستجو ارسال می‌شود که منجر به رندرهای مکرر و در نهایت افت عملکرد خواهد شد.

برای حل این مشکل، در هوک useSearch از مکانیزم debounce استفاده کرده‌ایم که صبر می‌کند تا کاربر تایپ کردن را متوقف کند، سپس جستجو را انجام می‌دهد. در ادامه، هوک useDebounce را داریم:

import React from "react";

function useDebounce(value, delay) {
    const [debouncedValue, setDebouncedValue] = React.useState(value);

    React.useEffect(() => {
        const timeoutId = setTimeout(() => {
            setDebouncedValue(value);
        }, delay);

        return () => clearTimeout(timeoutId);
    }, [value, delay]);

    return debouncedValue;
}

این هوک تضمین می‌کند که جستجو فقط پس از ۳۰۰ میلی‌ثانیه عدم فعالیت کاربر اجرا شود. به این ترتیب از رندرهای غیرضروری جلوگیری شده و واکنش‌پذیری برنامه افزایش می‌یابد.

بهینه‌سازی عملکرد جستجو در React با React.useMemo

فیلتر کردن داده‌های حجیم می‌تواند پردازشی سنگین باشد. اگر منطق جستجوی ما در هر بار رندر شدن کامپوننت اجرا شود،حتی زمانی که کوئری تغییری نکرده باشد، می‌تواند باعث افت سرعت شود. در این‌جا React.useMemo() به کمک ما می‌آید.

با قرار دادن منطق جستجو در هوک useMemo، اطمینان حاصل می‌کنیم که فقط زمانی محاسبه دوباره انجام شود که کوئری، فیلترها یا داده‌ها واقعاً تغییر کرده باشند:

return React.useMemo(() => {
    // Filtering logic
}, [data, debouncedQuery, filters]);

اما این کار چقدر تفاوت ایجاد می‌کند؟ تصور کنید یک کامپوننت parent داریم با یک state بی‌ربط (مثل یک شمارنده). هر بار که کامپوننت parent رندر می‌شود، در حالت بدون useMemo، جستجو مجدداً اجرا می‌شود، حتی اگر کوئری ثابت مانده باشد.

با استفاده از هوک useMemo، منطق جستجو فقط زمانی اجرا می‌شود که کوئری، فیلترها یا داده‌ها تغییر کنند. این کار باعث می‌شود عملکرد برنامه روان‌تر باشد و از محاسبات غیرضروری جلوگیری شود.

چگونگی اتصال فیلترها با متد ()reduce در جستجوی پیشرفته React

در این هوک از متد .reduce() استفاده می‌کنیم تا فیلترها را به‌صورت پشت‌سرهم روی داده‌ها اعمال کنیم. این روش باعث می‌شود منطق جستجو تمیز، قابل فهم و قابل توسعه باقی بماند:

return filters.reduce(
    (acc, feature) => feature(acc, debouncedQuery),
    dataArray
);

این رویکرد همچنین اضافه یا حذف کردن فیلترهای جدید را بسیار ساده می‌کند.

چگونه فیلترهای کارآمد برای جستجوی پیشرفته در React ایجاد کنیم؟

فیلترها در پیاده‌سازی جستجو پیشرفته React نقش کلیدی دارند. آن‌ها مسئول پردازش داده‌ها بر اساس کوئری ورودی هستند. در این پروژه، دو نوع فیلتر طراحی شده است: یکی برای عملیات جستجو و دیگری برای مدیریت Pagination.

۱. فیلتر جستجو

فیلتر جستجو، فیلدهای مشخص‌شده در هر آبجکت را بررسی می‌کند تا ببیند آیا با کوئری مطابقت دارند یا نه. این فیلتر از چندین روش تطبیق (matching) پشتیبانی می‌کند:

  • exact
  • startsWith
  • endsWith
  • contains
// utils/search.js

export function search(options) {
    const { fields, matchType } = options;

    return (data, query) => {
        const trimmedQuery = String(query).trim().toLowerCase();

        if (!trimmedQuery) return data;

        return data.filter((item) => {
            const fieldsArray = fields
                ? Array.isArray(fields)
                    ? fields
                    : [fields]
                : getAllKeys(item);

            return fieldsArray.some((field) => {
                const fieldValue = getFieldValue(item, field);
                if (fieldValue == null) return false;

                const stringValue = convertToString(fieldValue).toLowerCase();

                switch (matchType) {
                    case "exact":
                        return stringValue === trimmedQuery;
                    case "startsWith":
                        return stringValue.startsWith(trimmedQuery);
                    case "endsWith":
                        return stringValue.endsWith(trimmedQuery);
                    case "contains":
                        return stringValue.includes(trimmedQuery);
                    default:
                        throw new Error(`Unsupported match type: ${matchType}`);
                }
            });
        });
    };
}

بیایید نگاهی به مراحل عملکرد این فیلتر بیندازیم:

۱. پاک‌سازی کوئری:

const trimmedQuery = String(query).trim().toLowerCase();

if (!trimmedQuery) {
    return data;
}

در این مرحله، جستجو حساسیت به حروف بزرگ و کوچک ندارد و فاصله‌های اضافی حذف می‌شوند.

۲. تعیین فیلدهایی که باید جستجو شوند:

const fieldsArray = fields
    ? Array.isArray(fields)
        ? fields
        : [fields]
    : getAllKeys(item);

اگر فیلدهای خاصی مشخص نشده باشند، تمام کلیدها از جمله کلیدهای تودرتو استخراج می‌شوند.

۳. فیلتر کردن داده‌ها:

return fieldsArray.some((field) => {
    const fieldValue = getFieldValue(item, field);

    if (fieldValue == null) {
        return false;
    }

    const stringValue = convertToString(fieldValue).toLowerCase();

    // Matching logic based on matchType follows...
});

۲. توابع کمکی

برای حفظ سادگی و تمرکز در منطق فیلترسازی در جستجو پیشرفته React، از چند تابع کمکی بهره می‌بریم. این توابع وظایفی مانند استخراج کلیدهای آبجکت‌ها، دسترسی به مقادیر تودرتو و تبدیل آن‌ها به رشته را انجام می‌دهند. با این ساختار، فیلتر جستجو می‌تواند بدون پیچیده شدن منطق اصلی، انواع مختلف داده را پردازش کند.

استخراج همه کلیدها با getAllKeys:

تابع getAllKeys یک آبجکت را اسکن می‌کند تا تمام کلیدهای آن را جمع‌آوری کند، حتی کلیدهایی که درون آرایه‌ها یا آبجکت‌های تودرتو قرار دارند. اگر فیلدهای خاصی برای جستجو مشخص نشده باشد، این تابع تضمین می‌کند که تمام فیلدهای ممکن در نظر گرفته شوند.

// utils/getAllKeys.js

  export function getAllKeys(item, prefix = "") {
      if (!item || typeof item !== "object") {
          return [];
      }

      const fields = [];

      for (const key of Object.keys(item)) {
          const value = item[key];
          const fieldPath = prefix ? `${prefix}.${key}` : key;

          if (Array.isArray(value)) {
              value.forEach((arrayItem, index) => {
                  if (
                      arrayItem &&
                      typeof arrayItem === "object" &&
                      !(arrayItem instanceof Date)
                  ) {
                      fields.push(...getAllKeys(arrayItem, `${fieldPath}[${index}]`));
                  } else {
                      fields.push(`${fieldPath}[${index}]`);
                  }
              });
          } else if (value instanceof Date) {
              fields.push(fieldPath);
          } else if (value && typeof value === "object") {
              fields.push(...getAllKeys(value, fieldPath));
          } else {
              fields.push(fieldPath);
          }
      }

      return fields;
  }

استخراج مقدار فیلدها با getFieldValue:

تابع getFieldValue مقدار یک فیلد خاص را با استفاده از مسیر آن (مثل "user.name" یا "items[0].title") از یک آبجکت استخراج می‌کند. این تابع مسیر را به کلیدهای جداگانه تقسیم کرده و به‌صورت مرحله‌به‌مرحله آبجکت را پیمایش می‌کند تا مقدار مورد نظر را پیدا کند.

// utils/getFieldValue.js

  export function getFieldValue(item, field) {
      const keys = field.split(/[\.\[\]]/).filter(Boolean);
      let value = item;

      for (const key of keys) {
          if (value == null) {
              return null;
          }
          value = value[key];
      }

      return value;
  }

تبدیل مقادیر به رشته با convertToString:

برای مقایسه‌های جستجو، لازم است تمام داده‌ها به فرمت رشته‌ای تبدیل شوند. تابع convertToString این کار را انجام می‌دهد. این تابع تاریخ‌ها را به فرمت ISO و مقادیر بولین را به رشته‌های "true" یا "false" تبدیل می‌کند تا فیلتر جستجو با فرمتی یکنواخت و قابل اطمینان کار کند.

// utils/convertToString.js

 export function convertToString(value) {
     if (value instanceof Date) {
         return value.toISOString();
     }

     if (typeof value === "boolean") {
         return value ? "true" : "false";
     }

     return String(value);
 }

۳. فیلتر صفحه‌بندی

برای مجموعه داده‌های بزرگ، نمایش همه نتایج به‌طور هم‌زمان عملی نیست. فیلتر صفحه‌بندی (Pagination) با بازگرداندن فقط یک زیرمجموعه از داده‌ها براساس صفحه فعلی و تعداد آیتم‌ها در هر صفحه، هم عملکرد را بهبود می‌بخشد و هم داده‌ها را برای کاربر قابل مدیریت‌تر می‌سازد.

در این تابع، شاخص شروع با استفاده از شماره صفحه و اندازه صفحه محاسبه می‌شود. سپس با متد slice در جاوااسکریپت، تنها آیتم‌های مربوط به آن صفحه انتخاب می‌شوند. پارامتر query در اینجا نقشی ندارد و فقط برای حفظ یکپارچگی رابط هوک استفاده شده است.

// utils/paginate.js

export function paginate(options) {
    const { page = 1, pageSize = 10 } = options;

    return (data, query) => {
        // Query is not used here; it’s only for compatibility with our hook.
        const startIndex = (page - 1) * pageSize;

        return data.slice(startIndex, startIndex + pageSize);
    };
}

در این کد، فیلتر Pagination آرایه داده‌ها را به‌صورت بهینه برش می‌دهد تا تنها زیرمجموعه‌ای از نتایج که در صفحه فعلی باید نمایش داده شوند، بازگردانده شوند.

نحوه استفاده از هوک useSearch همراه با فیلترهای جستجو و صفحه‌بندی در React 

حالا که فیلترهای جستجو و صفحه‌بندی را آماده کردیم، بررسی می‌کنیم تا ببینیم چطور می‌توانیم آن‌ها را در یک کامپوننت React استفاده کنیم.

در مرحله اول، هوک سفارشی useSearch و توابع فیلتر را import می‌کنیم.

import useSearch from "./hooks/useSearch.js";
import search from "./utils/search.js";
import paginate from "./utils/paginate.js";

سپس، یک کامپوننت می‌سازیم که از این فیلترها استفاده کند. در این مثال، ما یک آرایه از آیتم‌ها داریم و می‌خواهیم بر اساس نام جستجو کنیم و تعداد مشخصی از نتایج را در هر صفحه نمایش دهیم. همچنین، هر زمان که کاربر یک کوئری جستجوی جدید وارد کند، به صفحه اول باز می‌گردیم.

function SearchComponent() {
    // Example data array
    const data = [
        { name: "JavaScript" },
        { name: "Python" },
        { name: "Java" },
        { name: "Ruby" },
        // Imagine more data here
    ];

    const [query, setQuery] = React.useState("");
    const [page, setPage] = React.useState(1);
    const pageSize = 3; // Items per page

    // Apply both search and pagination filters with our custom hook.
    const results = useSearch(
        data,
        query,
        search({
            fields: ["name"],
            matchType: "contains", // Options: "exact", "startsWith", etc.
        }),
        paginate({ page, pageSize })
    );

    // Compute total pages based on filtered results (without pagination)
    const filteredData = search({ fields: ["name"], matchType: "contains" })(
        data,
        query
    );

    const totalPages = Math.ceil(filteredData.length / pageSize);

    return (
        <div style={{ padding: "20px", fontFamily: "Arial, sans-serif" }}>
            <h2>Search and Pagination</h2>
            <input
                type="text"
                value={query}
                onChange={(e) => {
                    setQuery(e.target.value);
                    setPage(1); // Reset to first page on new search
                }}
                placeholder="Search by name..."
                style={{ padding: "8px", width: "300px", marginBottom: "10px" }}
            />
            <ul>
                {results.map((item, index) => (
                    <li key={index}>{item.name}</li>
                ))}
            </ul>
            <div style={{ marginTop: "10px" }}>
                <button
                    onClick={() => setPage((prev) => Math.max(prev - 1, 1))}
                    disabled={page === 1}
                    style={{ padding: "6px 12px", marginRight: "10px" }}
                >
                    Previous
                </button>
                <span>Page {page} of {totalPages}</span>
                <button
                    onClick={() => setPage((prev) => Math.min(prev + 1, totalPages))}
                    disabled={page >= totalPages}
                    style={{ padding: "6px 12px", marginLeft: "10px" }}
                >
                    Next
                </button>
            </div>
        </div>
    );
}

مدیریت اشتباهات تایپی در جستجوی پیشرفته React

جستجو یکی از قدیمی‌ترین قابلیت‌ها در وب است، اما این به معنای آن نیست که کاربران همیشه آن را به‌درستی انجام می‌دهند. در واقع، اشتباهات تایپی بسیار رایج هستند. تصور کنید کاربری قصد دارد واژه “PlayStation” را جستجو کند، اما به اشتباه “PlauStation” تایپ می‌کند. آن‌ها همچنان انتظار دارند نتایج مرتبط را ببینند، بنابراین سیستم جستجوی ما باید آن‌قدر هوشمند باشد که بتواند این اشتباهات جزئی را نادیده بگیرد.

برای رسیدن به این هدف، از تکنیکی به‌نام جستجوی مبهم (Fuzzy Search) استفاده می‌کنیم که کلمات مشابه را حتی در صورت تفاوت املایی، با یکدیگر تطبیق می‌دهد. ما این جستجوی مبهم را با استفاده از الگوریتمی به‌نام n-gram پیاده‌سازی می‌کنیم؛ این الگوریتم کلمات را به بخش‌های کوچک‌تری به نام n-gram تقسیم کرده و آن‌ها را با هم مقایسه می‌کند.

گام اول: ساخت الگوریتم شباهت n-gram برای جستجوی فازی در React

الگوریتم n-gram با تقسیم کوئری جستجو و مقادیر دیتاست به دنباله‌های کوچک و هم‌پوشان از کاراکترها (n-grams) کار می‌کند و سپس آن‌ها را با هم مقایسه می‌نماید:

// utils/nGramFuzzySearch.js

export const nGramFuzzySearch = (value, query) => {
    const n = 2; // Default to bigrams (two-character sequences)

    const valueGrams = generateNGrams(value.toLowerCase(), n);
    const queryGrams = generateNGrams(query.toLowerCase(), n);

    const intersection = valueGrams.filter((gram) => queryGrams.includes(gram));

    return intersection.length / Math.max(valueGrams.length, queryGrams.length);
};

const generateNGrams = (str, n) => {
    const grams = [];

    for (let i = 0; i <= str.length - n; i++) {
        grams.push(str.slice(i, i + n));
    }

    return grams;
};

به‌عنوان مثال، فرض کنید کاربر کلمه‌ی “PlauStation” را جستجو می‌کند و نام محصول “PlayStation” است.

در ابتدا، الگوریتم bigram (دنباله‌های دوحرفی) برای هر دو کلمه تولید می‌کند:

PlayStation → ["pl", "la", "ay", "ys", "st", "ta", "at", "ti", "io", "on"]
PlauStation → ["pl", "la", "au", "us", "st", "ta", "at", "ti", "io", "on"]

سپس، با محاسبه تعداد bigram‌های مشترک، میزان شباهت را می‌سنجد. هرچه میزان هم‌پوشانی بیشتر باشد، تطبیق قوی‌تر خواهد بود. چون اغلب bigramها در این مثال مشابه‌اند، الگوریتم امتیاز شباهت بالایی برمی‌گرداند و بنابراین می‌تواند “PlauStation” را به‌عنوان تطبیق مناسبی برای “PlayStation” تشخیص دهد، حتی با وجود اشتباه تایپی.

گام دوم: افزودن جستجوی مبهم به فیلتر جستجو در React

اکنون باید فیلتر جستجوی خود را به‌روزرسانی کنیم تا از یک matchType جدید برای جستجوی فازی پشتیبانی کند:

// Update in utils/search.js

import { nGramFuzzySearch } from "./nGramFuzzySearch";

export function search(options) {
    const { fields, matchType } = options;

    return (data, query) => {
        const trimmedQuery = String(query).trim().toLowerCase();

        if (trimmedQuery === "") {
            return data;
        }

        return data.filter((item) => {
            const fieldsArray = fields
                ? Array.isArray(fields)
                    ? fields
                    : [fields]
                : getAllKeys(item);

            return fieldsArray.some((field) => {
                const fieldValue = getFieldValue(item, field);
                if (fieldValue == null) {
                    return false;
                }

                const stringValue = convertToString(fieldValue).toLowerCase();

                switch (matchType) {
                    case "exact":
                        return stringValue === trimmedQuery;
                    case "startsWith":
                        return stringValue.startsWith(trimmedQuery);
                    case "endsWith":
                        return stringValue.endsWith(trimmedQuery);
                    case "contains":
                        return stringValue.includes(trimmedQuery);
                    case "fuzzySearch": {
                        const threshold = 0.5; // Minimum similarity score required
                        const score = nGramFuzzySearch(stringValue, trimmedQuery);
                        return score >= threshold;
                    }
                    default:
                        throw new Error(`Unsupported match type: ${matchType}`);
                }
            });
        });
    };
}

گام سوم: استفاده از جستجوی مبهم در هوک useSearch در React

اکنون می‌توانیم تنها با ارسال fuzzySearch به‌عنوان matchType، جستجوی مبهم را فعال کنیم:

const results = useSearch(
    data,
    query,
    search({
        fields: ["name"],
        matchType: "fuzzySearch",
    })
);

استفاده از نسخه آماده هوک useSearch برای جستجو پیشرفته در React

اگر تمایلی به ساخت همه چیز از صفر نداریم، جای نگرانی نیست. یک نسخه بهینه و آماده از هوک useSearch تحت عنوان use-search-react در npm منتشر شده است. این پکیج نه‌تنها قابلیت جستجو را فراهم می‌کند، بلکه پشتیبانی داخلی از مرتب‌سازی، صفحه‌بندی، گروه‌بندی، و انواع الگوریتم‌های جستجوی مبهم را نیز ارائه می‌دهد تا ما بتوانیم تمرکز خود را بر توسعه برنامه خود بگذاریم.

نحوه استفاده از هوک useSearch در کامپوننت‌های React

گام اول: نصب هوک

به‌سادگی پکیج را با npm نصب می‌کنیم:

npm install use-search-react

گام دوم: import و استفاده از هوک

استفاده از این هوک در کامپوننت ما بسیار ساده است. برای مثال، در ادامه کامپوننتی داریم که از این هوک برای انجام جستجوی مبهم بر روی یک آرایه داده استفاده می‌کند:

import { useSearch, search } from "use-search-react";
import { useState } from "react";

function SearchComponent() {
    const [query, setQuery] = useState("");

    const data = [
        { name: "JavaScript" },
        { name: "Python" },
        { name: "Java" }
    ];

    // The 'search' function here is configured to perform a fuzzy search.
    const results = useSearch(
        data,
        query,
        search({
            fields: ["name"],
            matchType: "fuzzy",
        })
    );

    return (
        <div>
            <input
                type="text"
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                placeholder="Search..."
            />
            <ul>
                {results.map((item, index) => (
                    <li key={index}>{item.name}</li>
                ))}
            </ul>
        </div>
    );
}

این مثال نشان می‌دهد که استفاده از این هوک در کامپوننت‌های React چقدر آسان است. این پکیج برای کار با دیتاست‌های بسیار بزرگ (تا ده‌ها هزار رکورد) نیز طراحی شده و همچنان عملکرد سریع و پاسخ‌گو دارد.

جمع‌بندی

ساخت یک سیستم جستجوی پیشرفته در React فراتر از صرفاً فیلتر کردن داده‌هاست. این کار به معنای خلق تجربه‌ای شهودی و پاسخ‌گو برای کاربران است.

در این مقاله آموختیم چگونه یک هوک سفارشی useSearch بسازیم که چالش‌های رایجی مانند عملکرد، داده‌های تودرتو و حتی اشتباهات تایپی کاربران را با جستجوی مبهم مدیریت کند. همچنین با استفاده از Pagination، توانستیم داده‌های بزرگ را به‌صورت بهینه نمایش دهیم.

دیدگاه‌ها:

افزودن دیدگاه جدید