في هذه المقالة، سنستكشف كيفية إنشاء صفحة موجز باستخدام React Query!
إليك ما سنقوم بإنشائه:
لن تغطي هذه المقالة كل خطوة وتفاصيل تتعلق بإنشاء التطبيق.
وبدلاً من ذلك، سنركز على الميزات الرئيسية، وتحديدًا وظائف "التمرير اللانهائي" و"التمرير إلى الأعلى".
إذا كنت مهتمًا بمراجعة التنفيذ بالكامل، فيمكنك العثور على قاعدة التعليمات البرمجية الكاملة في مستودع GitHub هذا.
أولاً، سنقوم بإنشاء تطبيق React الخاص بنا باستخدام Vite باستخدام الأمر التالي:
npm create vite@latest feed-page-rq -- --template react-ts
وسوف نقوم بتثبيت التبعيات المطلوبة، axios و react-query:
npm install axios @tanstack/react-query@4
نحتاج أيضًا إلى محاكاة خادم RESTful، لذلك سنستخدم json-server، والذي يسمح لنا بمحاكاة الواجهة الخلفية من خلال توفير نقاط نهاية API وهمية لتطبيق React الخاص بنا.
سنعمل مع كيان منشور يتضمن السمات التالية:
{ "id": "1", "title": "Sample Post Title", "body": "This is a sample post body", "userId": "2", "createdAt": 1728334799169 // date timestamp }
بمجرد إعداد الخادم، سنقوم بتشغيله باستخدام:
npx json-server --watch db.json
آلية ميزة "التمرير اللانهائي" واضحة ومباشرة:
عندما يقوم المستخدم بالتمرير عبر قائمة المنشورات ويقترب من أسفل الحاوية، سيبحث React Query عن الدفعة التالية من المنشورات. تتكرر هذه العملية حتى لا يكون هناك المزيد من المشاركات للتحميل.
نتحقق مما إذا كان المستخدم بالقرب من الأسفل عن طريق إضافة موضع التمرير الحالي (scrollTop) إلى ارتفاع الشاشة المرئي (clientHeight) ومقارنة هذا المجموع مع الارتفاع الإجمالي للحاوية (ارتفاع التمرير).
إذا كان المجموع أكبر من أو يساوي إجمالي ارتفاع الحاوية، فإننا نطلب من React Query جلب الصفحة التالية.
const { scrollTop, scrollHeight, clientHeight } = elemRef.current; if(scrollTop clientHeight >= scrollHeight) { fetchNextPage(); }
أولاً، سنقوم بإنشاء رابط مخصص لتغليف useInfiniteQuery الخاص بـ React Query.
ضمن الرابط المخصص، نقوم بتكوين الاستعلام لجلب المنشورات صفحة تلو الأخرى، مع تحديد رقم الصفحة الأولي والوظيفة التي تسترد الصفحات التالية:
import { QueryFunctionContext, useInfiniteQuery } from "@tanstack/react-query"; import axios from "axios"; const URL = "http://localhost:3000"; const POSTS = "posts"; export const fetchInfinitePosts = async ({ pageParam, }: QueryFunctionContext) => { const result = await axios.get( `${URL}/${POSTS}?_sort=-createdAt&_page=${pageParam}&_per_page=10`, ); return result.data; }; export const useInfinitePosts = () => { return useInfiniteQuery({ queryKey: [POSTS], queryFn: fetchInfinitePosts, initialPageParam: 1, getNextPageParam: (lastPage) => lastPage.next, }); };
الآن، سوف نستخدم الرابط المخصص في المكون الخاص بنا لعرض قائمة المنشورات.
للقيام بذلك، نقوم أولاً بتكرار الصفحات ثم نكررها على المنشورات داخل كل صفحة لعرضها.
import { useInfinitePosts } from './hooks/useInfinitePosts'; const PostList = () => { const { data: postLists } = useInfinitePosts(); return ({postLists?.pages.map((page) => page.data.map(post => (); }; export default PostList;)) )}{post.title}
{post.body}
لتنفيذ سلوك التمرير اللانهائي، نحتاج إلى إضافة مستمع لحدث التمرير إلى الحاوية التي يتم عرض المنشورات فيها. يقوم مستمع الحدث بتشغيل وظيفة onScroll، التي تتحقق مما إذا كان المستخدم بالقرب من الجزء السفلي من الحاوية، وإذا كان الأمر كذلك، فإنه يستدعي fetchNextPage لتحميل المزيد من المحتوى.
import React, { useRef, useEffect } from 'react'; import { useInfinitePosts } from './hooks/useInfinitePosts'; const PostList = () => { const { data: postLists, fetchNextPage } = useInfinitePosts(); const elemRef = useRef(null); const onScroll = useCallback(() => { if (elemRef.current) { const { scrollTop, scrollHeight, clientHeight } = elemRef.current; const isNearBottom = scrollTop clientHeight >= scrollHeight; if(isNearBottom) { fetchNextPage(); } } }, [fetchNextPage]); useEffect(() => { const innerElement = elemRef.current; if (innerElement) { innerElement.addEventListener("scroll", onScroll); return () => { innerElement.removeEventListener("scroll", onScroll); }; } }, [onScroll]); return ({postLists?.pages.map((page, i) => page.data.map(post => (); }; export default PostList;)) )}{post.title}
{post.body}
بعد ذلك، سنقوم بإنشاء زر "التمرير إلى الأعلى" الذي يظهر عند إضافة مشاركة جديدة. يتيح هذا الزر للمستخدم العودة بسرعة إلى الأعلى لرؤية آخر تحديث.
وبما أن المشاركات يتم فرزها حسب تاريخ الإنشاء، فإن أي مشاركة تمت إضافتها حديثًا ستظهر في أعلى القائمة.
سيتم بناء منطق الميزة لدينا على أساس هذه الفرضية.
نبدأ بإنشاء استعلام جديد لجلب آخر منشور تم إنشاؤه وتخزينه مؤقتًا. سوف نسمي هذا المنشور بـ prevNewestPost.
نريد أن يظل prevNewestPost متأخرًا ببضع خطوات، أو على الأكثر، يطابق المنشور الأول في القائمة. لذلك، سوف نتحكم يدويًا في إعادة جلبه.
سوف نحقق ذلك من خلال وضع تمكين: خطأ في خيارات الاستعلام.
export const fetchNewestPost = async () => { const result = await axios.get(`${URL}/${POSTS}?_sort=-createdAt`); return result.data[0]; }; export const useNewestPost = () => { return useQuery({ queryKey: [POSTS, "newest"], queryFn: () => fetchNewestPost(), enabled: false, }); };
باستخدام React Query، يتم تحديث قائمة المنشورات تلقائيًا في أحداث محددة. (إليك رابط التوثيق للحصول على قائمة كاملة بهذه الأحداث.)
سوف نستخدم هذه القائمة المحدثة لتحديد وقت عرض زر "التمرير إلى الأعلى" من خلال مقارنة prevNewestPost بالمنشور الأول.
إذا كانت مختلفة، فهذا يشير إلى أنه قد تمت إضافة مشاركة جديدة، لذلك سيظهر زر "التمرير إلى الأعلى".
setIsShowButton(postLists?.pages[0].data[0].id !== prevNewestPost?.id);
لا ينبغي أن نظهر زر "التمرير إلى الأعلى" عندما يكون المستخدم في أعلى حاوية قائمة المشاركات.
لذلك، عندما يصل المستخدم إلى الأعلى، نحتاج إلى إعادة مزامنة NewestPost السابق مع آخر مشاركة حالية عن طريق تشغيل إعادة جلب الاستعلام.
const { data: prevNewestPost, refetch } = useNewestPost(); const [isShowButton, setIsShowButton] = useState(false); useEffect(() => { if (!isNearTop) { setIsShowButton(postLists?.pages[0].data[0].id !== prevNewestPost?.id); } else { setIsShowButton(false); refetch(); } }, [postLists, prevNewestPost, isNearTop]);
سيؤدي النقر فوق زر ToTopBtn إلى التمرير إلى أعلى القائمة، مما يؤدي إلى تشغيل المنطق الموجود لإخفاء الزر وإعادة جلب البيانات لمزامنة المنشور السابق مع المنشور الأول في القائمة.
import { RefObject } from "react"; type ToTopBtnProps = { elemRef: RefObject; }; export default function ToTopBtn({ elemRef }: ToTopBtnProps) { return ( ); }
لاختبار وظيفة زر "التمرير إلى الأعلى"، نحتاج إلى إضافة منشورات جديدة إلى الموجز.
لهذا، سنستخدم useMutation من React Query لإضافة منشور جديد إلى الخادم وإعادة التحقق من قائمة النشرات المخزنة مؤقتًا بعد كل تغيير.
سنقوم بإعداد طفرة تسمح لنا بإنشاء منشور جديد يحتوي على بيانات عشوائية عندما ينقر المستخدم على زر.
export const savePost = async (post: NewPostData) => axios.post(`${URL}/${POSTS}`, post); export const useAddPost = () => { const queryClient = useQueryClient(); return useMutation({ mutationFn: savePost, onSuccess: () => { queryClient.invalidateQueries({ queryKey: [POSTS] }); }, }); };
export default function AddNewPostBtn() { const mutation = useAddPost(); return ();
في هذا البرنامج التعليمي، استكشفنا قوة React Query من خلال حالة استخدام حقيقية، مع تسليط الضوء على قدرتها على مساعدة المطورين في بناء واجهات ديناميكية تعمل على تحسين تجربة المستخدم.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3