نحوه ایجاد اسکرول بی نهایت در React با استفاده از Intersection Observer API

سلام به توسعه دهندگان همکار آیا تا به حال به این فکر کرده اید که چگونه برنامه های رسانه های اجتماعی مانند فیس بوک و اینستاگرام باعث می شوند تا بی نهایت در فید خود پیمایش کنید؟
این تجربه کاربری که برای بارگذاری محتوای جدید در صورت تقاضا طراحی شده است، از تکنیکی به نام اسکرول بی نهایت استفاده می کند. این به شما کمک می کند ساعت ها به این برنامه ها متصل شوید.
به طور سنتی، این ویژگیها باعث میشوند که برای نمایش محتوای جدید روی «صفحه بعدی» کلیک کنید. با این حال، پیمایش بینهایت با واکشی دادههای کمتر در یک زمان، بار روی سرور را کاهش میدهد و پس ، تجربه کاربر بسیار جذابتری را ارائه میدهد.
در این پست قصد داریم همین ویژگی را در جاوا اسکریپت پیاده سازی کنیم. هنگامی که کاربر در حال پیمایش است، از Intersection Observer API برای بارگیری داده ها در صورت تقاضا استفاده می کنیم. ما یک برنامه ساده React ایجاد خواهیم کرد که پستهای مشابه فید رسانههای اجتماعی را نمایش میدهد.
نحوه راه اندازی اپلیکیشن React
create-react-app
در ترمینال خود اجرا کنید یا از یک ابزار مدرن ساخته شده مانند Vite برای ایجاد برنامه React خود استفاده کنید. کد دیگ بخار موجود را حذف کنید. نیازی به نصب وابستگی اضافی نیست. دستور npm start
را برای شروع پروژه اجرا کنید.
کد کامل این آموزش را می توانید در GitHub بیابید. بیا شروع کنیم.
نحوه ایجاد تابع واکشی داده
یک فایل جداگانه به نام services.js
ایجاد کنید و تابع واکشی داده زیر را بنویسید.
ما از /posts
API از JSONPlaceholder برای دریافت داده های خود استفاده خواهیم کرد.
export const fetchPosts = async (page, limit) => { const response = await fetch( `https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${limit}` ); const data = await response.json(); return data; };
در اینجا، ما دو پارامتر را به API ارسال کرده ایم:
page
نشان دهنده بخشی از داده است که فراخوانی می شود. هر بار که کاربر پیمایش می کند و داده های جدید را بارگذاری می کند، این مقدار افزایش می یابد.
limit
نشان دهنده مقدار داده ای است که در یک زمان فراخوانی می شود. برای پیمایش بینهایت، دادههای کافی را میخوانیم که بتوان در یک صفحه نمایش داد.
چگونه کامپوننت اسکرول بی نهایت بسازیم
بیایید یک کامپوننت PostsList
برای نمایش فهرست ی از پست ها با اسکرول بی نهایت ایجاد کنیم.
بیایید متغیرهای حالت خود را ایجاد کنیم، داده ها را واکشی کنیم و آن را نمایش دهیم:
const PostsList = () => { const [posts, setPosts] = useState([]); const [page, setPage] = useState(1); const [loading, setLoading] = useState(false); return ( <div> <h1>Your Feed</h1> <ul> {posts.map((post, index) => ( <li key={post.id} > <h2>{post.title}</h2> <p>{post.body}</p> </li> ))} </ul> {loading && <p>Loading...</p>} </div> ); };
در اینجا متغیرهای وضعیت پست ها، شماره صفحه و وضعیت بارگذاری را تعریف کرده ایم. توجه داشته باشید که شماره صفحه به معنای اضافه کردن صفحه بندی نیست. این فقط یک پارامتر برای بارگیری مجموعه بعدی داده است.
اکنون، اجازه دهید API خود را با شماره صفحه فعلی فراخوانی کنیم و وضعیت های بارگیری را تنظیم کنیم:
const loadMorePosts = async () => { setLoading(true); const newPosts = await fetchPosts(page, 10); setPosts((prevPosts) => [...prevPosts, ...newPosts]); setLoading(false); }; useEffect(() => { loadMorePosts(); }, [page]);
تا به حال، ما 10 پست اولیه را در اولین بارگذاری صفحه دریافت کرده ایم. وقتی کاربر صفحه را به پایین اسکرول می کند، قصد داریم داده های بیشتری بارگیری کنیم.
در مرحله بعد، از Intersection Observer API برای تشخیص زمان بارگیری داده های اضافی استفاده می کنیم.
قبل از استفاده از آن، اجازه دهید ابتدا بفهمیم که این API چیست.
Intersection Observer API چیست؟
Intersection Observer API یک API وب است که به شما امکان می دهد به طور ناهمزمان تغییرات را در تقاطع یک عنصر هدف با یک عنصر اجداد یا درگاه مشاهده مشاهده کنید.
به عبارت سادهتر، به شما امکان میدهد تشخیص دهید که چه زمانی یک عنصر وارد یا خارج میشود در یک منطقه از عنصر DOM دیگر یا درگاه دید. استفاده از Intersection Observer مزایای زیر را برای ما فراهم می کند:
نیاز به پیوست کردن شنوندگان رویداد به هر رویداد اسکرول را کاهش میدهد.
نیاز به محاسبات دستی موقعیت عنصر و شنوندگان رویداد آنها را برطرف می کند، پس کد شما را ساده می کند.
کارآمد برای مشاهده چندین رویداد در مقایسه با اسکرول یا تغییر اندازه شنوندگان رویداد.
برای درک بیشتر درباره Intersection Observer ، اسناد MDN را مرور کنید.
نحوه استفاده از Intersection Observer API
برای استفاده از این API، باید یک شی ناظر ایجاد کنیم.
در اینجا نحوه ایجاد یک شی ناظر آمده است:
const observer = new IntersectionObserver(callback, options);
callback
تابعی است که زمانی فراخوانی می شود که دید عنصر مشاهده شده تغییر کند. این تابع دو آرگومان می گیرد: entries
و خود شی observer
. هر شی در آرایه entries
یک شی IntersectionObserverEntry
است که حاوی اطلاعاتی درباره وضعیت تقاطع عنصر مشاهده شده است.
options
یک آرگومان اختیاری برای پیکربندی بیشتر Observer است.
چگونه از این در برنامه خود استفاده کنیم؟ ما شی ناظر را به عنوان یک ref تعریف می کنیم:
const observer = useRef();
حال، برای تنظیم این شی ناظر بر روی یک عنصر و تشخیص اینکه آیا آن عنصر با ویوپورت تلاقی دارد یا خیر، از تابع زیر استفاده می کنیم که یک ref برگشتی است:
const lastPostElementRef = useCallback( (node) => { if (loading) return; if (observer.current) observer.current.disconnect(); observer.current = new IntersectionObserver((entries) => { if (entries[0].isIntersecting) { setPage((prevPage) => prevPage + 1); // trigger loading of new posts by chaging page no } }); if (node) observer.current.observe(node); }, [loading] );
بیایید نحوه عملکرد این تابع را درک کنیم:
تحلیل می کنیم که آیا داده ها هنوز در حال بارگیری هستند یا خیر. اگر اینطور باشد، منطق را اجرا نمی کنیم.
برای رجوع به شی observer
، از ویژگی current
ref استفاده می کنیم.
اگر عنصری از قبل مشاهده میشود، آن را قطع کنید و یک مشاهدهگر جدید ایجاد کنید که شماره صفحه را تغییر میدهد، پس اگر عنصر مشاهدهشده با درگاه نمایش تلاقی کرد، فراخوانی API را راهاندازی میکند.
از آنجایی که ما فقط یک عنصر را در یک زمان مشاهده می کنیم (مانند آخرین عنصر صفحه)، اندازه entries
یک است.
این Observer جدید اکنون عنصر فعلی را که ref به آن متصل است، که آخرین عنصر در صفحه است، تماشا خواهد کرد.
از آنجایی که ما فقط میخواهیم آخرین عنصر صفحه را مشاهده کنیم، این ref را طبق شرایط زیر اضافه میکنیم:
{posts.map((post, index) => ( <li key={post.id} ref={posts.length === index + 1 ? lastPostElementRef : null} > ... </li> ))}
حال، چرا به جای استفاده از خود observer
از refs callback استفاده می کنیم؟
یک ref یک ارجاع مستقیم به عنصر به ما می دهد و مقدار شی ref را مستقیماً تعیین می کند. برای عناصری که نیازی به تغییر دینامیک مرجع ندارند به خوبی کار می کند.
یک پاسخ برگشتی کنترل بیشتری بر روی ref ارائه می دهد و می تواند تغییرات پویا را برای ارجاع موثرتر مدیریت کند. این تابعی است که با نمونه عنصر، یا گره DOM آن هنگام سوار شدن کامپوننت، نامیده می شود و در صورت جدا شدن، با null خوانده می شود.
در مورد ما، مرجع ما به صورت پویا تغییر می کند زیرا آخرین عنصر ما با بارگیری داده های بیشتر به روز می شود. همچنین میتوانیم منطقی برای مشاهده و قطع ارتباط با یک گره بنویسیم، در حالی که شی ref خود را تنظیم میکنیم.
ما همچنین تابع lastPostElementRef
را در داخل یک قلاب useCallback
قرار می دهیم تا در هر رندر مجدد ایجاد نشود. ما فقط در صورتی این تابع را ایجاد می کنیم که حالت بارگذاری زمانی که زمان اجرای تابع باشد تغییر کند.
برنامه خود را با npm start
اجرا کنید، به http://localhost:3000
بروید و برگه Network را باز کنید. همانطور که به پایین اسکرول می کنید، با اسکرول کردن صفحه به پایین، درخواست های جدید API را مشاهده خواهید کرد.

کد کامل را می توانید در GitHub و آموزش های مشابه در جاوا اسکریپت و ری اکت پیدا کنید.
نتیجه
هنگامی که پیمایش بینهایت را در برنامه خود پیادهسازی میکنید، تجربه کاربری یکپارچه و جذابی مشابه آنچه در برنامههای رسانههای اجتماعی محبوب میبینید، ارائه میدهد. به جای کلیک کردن روی صفحات، کاربران می توانند بدون زحمت در محتوایی که به صورت پویا بارگیری می شود، پیمایش کنند.
در مثال خود، ما یک فید رسانه اجتماعی ساختگی ایجاد کردیم که با پایین آمدن کاربر، محتوای بیشتری بارگیری می کرد. ما از Intersection Observer API برای شناسایی موقعیت آخرین عنصری که بر اساس آن داده های بیشتری را بارگذاری کردیم، استفاده کردیم. کد ما را ساده کرد و نیاز به پیوست کردن چندین شنونده رویداد را حذف کرد.
امیدوارم این به شما کمک کند تا ویژگی های مشابهی را در پروژه وب بعدی خود ایجاد کنید و به شما امکان دهد یک تجربه کاربری جذاب را ارائه دهید. لطفا نظرات و انتقادات خود را به اشتراک بگذارید. متشکرم!
ارسال نظر