از بارگذاری بیش از حد سرور با فراخوانی های غیر ضروری عملکرد جستجو خودداری کنید و عملکرد برنامه خود را با استفاده از این تکنیک بهینه کنید.
در React، هنگام اجرای عملکرد جستجو، کنترل کننده onChange هر بار که کاربر در کادر ورودی تایپ می کند، تابع جستجو را فراخوانی می کند. این رویکرد میتواند باعث مشکلات عملکرد شود، بهویژه در صورت برقراری تماسهای API یا جستجو در پایگاه داده. تماسهای مکرر با عملکرد جستجو ممکن است سرور وب را بیش از حد بارگذاری کند که منجر به خرابی یا عدم پاسخگویی رابط کاربری شود. حذف این مشکل را حل می کند.
Debouncing چیست؟
به طور معمول، عملکرد جستجو را در React با فراخوانی یک تابع کنترل کننده onChange در هر ضربه کلید مطابق شکل زیر پیاده سازی می کنید:
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Search for:", searchTerm);
};
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
handleSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
در حالی که این کار کار می کند، تماس با بخش پشتیبان برای به روز رسانی نتایج جستجو در هر فشار کلید ممکن است گران شود. به عنوان مثال، اگر به دنبال “webdev” بودید، برنامه درخواستی را با مقادیر “w”، “we”، “web” و غیره به باطن ارسال میکند.
Debouncing تکنیکی است که با به تاخیر انداختن اجرای یک تابع تا سپری شدن یک دوره تاخیر کار می کند. تابع debounce هر بار که کاربر تایپ می کند شناسایی می کند و از تماس با کنترل کننده جستجو تا زمان سپری شدن تاخیر جلوگیری می کند. اگر کاربر در مدت زمان تأخیر به تایپ کردن ادامه دهد، تایمر بازنشانی میشود و React عملکرد را برای تأخیر جدید دوباره فراخوانی میکند. این روند تا زمانی ادامه می یابد که کاربر تایپ را متوقف کند.
با منتظر ماندن کاربران برای توقف تایپ، بازگرداندن اطمینان حاصل می کند که برنامه شما فقط درخواست های جستجوی لازم را انجام می دهد و در نتیجه بار سرور را کاهش می دهد.
چگونه جستجو را در React از بین ببریم
چندین کتابخانه وجود دارد که می توانید برای پیاده سازی debounce از آنها استفاده کنید. همچنین می توانید انتخاب کنید که خودتان آن را از ابتدا با استفاده از توابع setTimeout و clearTimeout جاوا اسکریپت پیاده سازی کنید.
این مقاله از تابع debounce از کتابخانه lodash استفاده می کند.
با فرض اینکه یک پروژه React آماده دارید، یک کامپوننت جدید به نام Search ایجاد کنید. اگر پروژه کاری ندارید، با استفاده از ابزار Creative app React یک برنامه React ایجاد کنید.
در فایل کامپوننت جستجو، کد زیر را کپی کنید تا یک کادر ورودی جستجو ایجاد شود که در هر ضربه کلید یک تابع کنترل کننده را فراخوانی می کند.
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Search for:", searchTerm);
};
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
handleSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
برای حذف تابع handleSearch، آن را به تابع debounce از lodash ارسال کنید.
import debounce from "lodash.debounce";
import { useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = () => {
console.log("Search for:", searchTerm);
};
const debouncedSearch = debounce(handleSearch, 1000);
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
debouncedSearch();
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
در تابع debounce، تابعی را که میخواهید به تأخیر بیندازید، یعنی تابع handleSearch، و زمان تأخیر را بر حسب میلیثانیه، یعنی 500 میلیثانیه منتقل میکنید.
در حالی که کد بالا باید تماس با درخواست handleSearch را تا زمانی که کاربر تایپ را متوقف کند به تاخیر بیاندازد، اما در React کار نمی کند. دلیل آن را در بخش بعدی توضیح خواهیم داد.
Debouncing و Rerenders
این برنامه از یک ورودی کنترل شده استفاده می کند. این بدان معنی است که مقدار state مقدار ورودی را کنترل می کند. هر بار که کاربر در قسمت جستجو تایپ می کند، React وضعیت را به روز می کند.
در React، زمانی که یک مقدار حالت تغییر می کند، React کامپوننت را مجدداً نمایش می دهد و تمام توابع داخل آن را اجرا می کند.
در کامپوننت جستجوی بالا، وقتی کامپوننت دوباره رندر میشود، React تابع debounce را اجرا میکند. این عملکرد یک تایمر جدید ایجاد می کند که تاخیر را پیگیری می کند و تایمر قدیمی در حافظه قرار می گیرد. هنگامی که زمان آن سپری می شود، عملکرد جستجو را فعال می کند. این بدان معنی است که عملکرد جستجو هرگز بازگردانده نمی شود، 500 میلی ثانیه تاخیر دارد. این چرخه در هر رندر تکرار می شود – تابع یک تایمر جدید ایجاد می کند، تایمر قدیمی منقضی می شود و سپس تابع جستجو را فراخوانی می کند.
برای اینکه تابع debounce کار کند، فقط یک بار باید آن را فراخوانی کنید. می توانید این کار را با فراخوانی تابع debounce خارج از کامپوننت یا با استفاده از تکنیک یادداشت انجام دهید. به این ترتیب، حتی اگر کامپوننت دوباره رندر شود، React آن را دوباره اجرا نخواهد کرد.
تعریف تابع Debounce خارج از کامپوننت جستجو
تابع debounce را مانند شکل زیر به خارج از کامپوننت جستجو منتقل کنید:
import debounce from "lodash.debounce"
const handleSearch = (searchTerm) => {
console.log("Search for:", searchTerm);
};
const debouncedSearch = debounce(handleSearch, 500);
اکنون، در کامپوننت Search، debounce Search را فراخوانی کرده و عبارت جستجو را پاس کنید.
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
debouncedSearch(searchTerm);
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
تابع جستجو فقط پس از سپری شدن دوره تاخیر فراخوانی می شود.
به خاطر سپردن تابع Debounce
Memoizing به ذخیره کردن نتایج یک تابع و استفاده مجدد از آنها هنگام فراخوانی تابع با همان آرگومان ها اشاره دارد.
برای به خاطر سپردن تابع debounce، از قلاب useMemo استفاده کنید.
import debounce from "lodash.debounce";
import { useCallback, useMemo, useState } from "react";
export default function Search() {
const [searchTerm, setSearchTerm] = useState("");
const handleSearch = useCallback((searchTerm) => {
console.log("Search for:", searchTerm);
}, []);
const debouncedSearch = useMemo(() => {
return debounce(handleSearch, 500);
}, [handleSearch]);
const handleChange = (e) => {
setSearchTerm(e.target.value);
// Calls search function
debouncedSearch(searchTerm);
};
return (
<input
onChange={handleChange}
value={searchTerm}
placeholder="Search here..."
/>
);
}
توجه داشته باشید که تابع handleSearch را نیز در یک قلاب useCallback قرار داده اید تا مطمئن شوید که React فقط یک بار آن را فراخوانی می کند. بدون استفاده از قلاب useCallback، React تابع handleSearch را با هر رندر مجدد که وابستگیهای قلاب useMemo را تغییر میدهد اجرا میکند که به نوبه خود تابع debounce را فراخوانی میکند.
اکنون React فقط در صورتی تابع debounce را فراخوانی می کند که تابع handleSearch یا زمان تاخیر تغییر کند.
بهینه سازی جستجو با Debounce
گاهی اوقات، کاهش سرعت می تواند برای عملکرد بهتر باشد. هنگام رسیدگی به وظایف جستجو، به خصوص در مورد تماس های گران قیمت پایگاه داده یا API، استفاده از یک تابع debounce راه حلی است. این تابع یک تاخیر را قبل از ارسال درخواست های باطن معرفی می کند.
این به کاهش تعداد درخواستهای ارسال شده به سرور کمک میکند، زیرا فقط پس از سپری شدن تاخیر و توقف موقت تایپ توسط کاربر، درخواست را ارسال میکند. به این ترتیب، سرور با درخواست های بیش از حد بارگیری نمی شود و عملکرد کارآمد باقی می ماند.