{"id":12149,"date":"2026-10-12T13:11:56","date_gmt":"2026-10-12T04:11:56","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=12149"},"modified":"2026-10-13T17:28:55","modified_gmt":"2026-10-13T08:28:55","slug":"nextjs-sns-server-51-3","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/10\/12\/nextjs-sns-server-51-3\/","title":{"rendered":"[nextjs]SNS Server-51(myapp61+)[Pagenation]\u00a0"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffb \uc774\ubc88\uc5d0\ub294 \ud398\uc774\uc9c0\ub124\uc774\uc158 \uae30\ub2a5\uc758 \uad6c\uc870\ub97c \uc790\uc138\ud788 \uc0b4\ud3b4 \ubd05\uc2dc\ub2e4.<br>Now, let&#8217;s take a closer look at the structure of the pagination feature.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc774\uc804 \ud3ec\uc2a4\ud2b8\uc5d0\uc11c \ub370\uc774\ud130\uac00 app\/usersui\/[username]\/page.tsx\uc5d0\uc11c \uc2dc\uc791\ud574\uc11c app\/usersui\/[username]\/_components\/themes\/themeex\/Timeline.tsx\uae4c\uc9c0 \uc5b4\ub5bb\uac8c \ud758\ub7ec\uac00\ub294\uc9c0 \uc0b4\ud3b4 \ubcf4\uc558\uc2b5\ub2c8\ub2e4.<br>In the previous post, we examined how data flows from <code>app\/usersui\/[username]\/page.tsx<\/code> down to <code>app\/usersui\/[username]\/_components\/themes\/themeex\/Timeline.tsx<\/code>.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc774 \ud398\uc774\uc9c0\ub124\uc774\uc158 \ud30c\ud2b8\uc5d0\uc11c\ub294 \ucd08\uae30 \ub370\uc774\ud130\uac00 \ud654\uba74\uc5d0 \ud45c\uc2dc\ub41c \ud6c4\uc5d0 \uc2a4\ud06c\ub864\uc744 \ub0b4\ub9ac\uba74 \uc5b4\ub5bb\uac8c \ub370\uc774\ud130\uac00 \ub354 \ucd94\uac00\ub418\ub294 \uac74\uc9c0 \uc790\uc138\ud788 \uc0b4\ud3b4\ubd05\ub2c8\ub2e4.<br>In this pagination section, we take a detailed look at how additional data is loaded when scrolling down after the initial data is displayed on the screen.<\/p>\n\n\n\n<p>\ud83d\udcc1 \ud398\uc774\uc9c0\ub124\uc774\uc158 \ud750\ub984 \/ Pagination flow<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>1.\ub77c\uc6b0\ud2b8 \uc2e4\ud589 \/ Execute route\n- https:\/\/aloy-horizon.duckdns.org\/@user1\n- or https:\/\/aloy-horizon.duckdns.org\/usersui\/user1\n- page.tsx \uc2e4\ud589\n- ClientPage.tsx \ud30c\uc77c \ub85c\ub4dc \/ file load\n\n2.ClientPage.tsx \n- \ucd08\uae30 \ub370\uc774\ud130\ub85c\ub4dc \/ Initial data load\n- \ud14c\ub9c8 \ud638\ucd9c \/ Theme Call\n- \ud14c\ub9c8 \ub514\ub809\ud1a0\ub9ac\uc758 TimelinList.tsx\uc5d0 \ucd08\uae30 \ub370\uc774\ud130 \uc804\ub2ec\nPassing initial data to TimelinList.tsx in the theme directory.\n\n3.TimelinList.tsx\n- \ucd08\uae30\ub370\uc774\ud130 \ud0c0\uc784\ub77c\uc778\uc5d0 \ud45c\uc2dc\nDisplay initial data on the timeline\n- \uc2a4\ud06c\ub864 \ub0b4\ub824\uc11c \ucd08\uae30\ub370\uc774\ud130 \ub05d\uc5d0 \ub3c4\ub2ec\ud558\uba74 \ub370\uc774\ud130 \ucd94\uac00 \ud638\ucd9c \nCall for additional data when scrolling down and reaching the end of the initial data.\n- \ud638\ucd9c\ub41c \ub370\uc774\ud130\ub97c \ucd08\uae30\ub370\uc774\ud130 \ub4a4\uc5d0 \ubd99\uc774\uae30\nAppend the fetched data after the initial data.<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ucd08\uae30\ub370\uc774\ud130 \ub85c\ub4dc &#8211; ClientPage.tsx<\/p>\n\n\n\n<p>1)username\uc774 \ubc14\ub00c\uba74 \ucd08\uae30 \ub370\uc774\ud130\uac00 \ub85c\ub4dc\uac00 \uc2dc\uc791\ub429\ub2c8\ub2e4.<br>When the username changes, the initial data begins to load.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>useEffect(() =&gt; { ... ... }, <strong>&#91;username]);<\/strong><\/code><\/pre>\n\n\n\n<p>2)\ud0c0\uc784\ub77c\uc778 \ubd84\uae30\ub294 \ub85c\uadf8\uc778\ud55c \uacbd\uc6b0\uc640 \ub85c\uadf8\uc778 \ud558\uc9c0 \uc54a\uc740 \uacbd\uc6b0 \ubcf4\uc5ec\uc9c0\ub294 \ub370\uc774\ud130\uac00 \ub2e4\ub974\uae30 \ub54c\ubb38\uc5d0 \ud0c0\uc784\ub77c\uc778 \ubd84\uae30\ub97c \uc0ac\uc6a9\ud569\ub2c8\ub2e4.<br>Timeline branching is used because the data displayed differs depending on whether the user is logged in or not.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code># \ub85c\uadf8\uc778 \ud55c \uacbd\uc6b0 \/ If logged in\n# \ucfe0\ud0a4 \ud3ec\ud568\ud574\uc11c \uc804\uc1a1 \/ Send with cookies\n- credentials: 'include' \nconst homeRes = await fetch(`\/api\/v1\/timelines\/home?limit=20`, { credentials: 'include' });\n\n# \ub85c\uadf8\uc778 \ud558\uc9c0 \uc54a\uc740 \uacbd\uc6b0 \/ If not logged in\nconst pubRes = await fetch(`\/api\/v1\/timelines\/public?local=true&amp;limit=20`);<\/code><\/pre>\n\n\n\n<p>3) \ub370\uc774\ud130 \uc804\ub2ec\uacfc\uc815\uc740 <a href=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-admin\/post.php?post=12057&amp;action=edit\">[nextjs]SNS Server-51(myapp61+)[Active theme]<\/a> \uc774 \ud3ec\uc2a4\ud2b8\ub97c \ucc38\uc870\ud558\uc138\uc694<br>Please refer to the post &#8220;[nextjs]SNS Server-51(myapp61+)[Active theme]&#8221; for the data transmission process.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>... ...\nconst &#91;loading, setLoading] = useState(true);\n... ...  \n\/\/ \u2705 myapp61 \n  \/\/ - \uccab \ub85c\ub529: \ub85c\uadf8\uc778=home, \ube44\ub85c\uadf8\uc778=public local\n  \/\/ - Initial load: Logged in = Home; Not logged in = Public Local\n  useEffect(() =&gt; {\n... ...\n\n   <strong> \/\/ 2. \ud0c0\uc784\ub77c\uc778 \ubd84\uae30 \/ Timeline branching<\/strong>\n    if (me) {\n      \/\/ \ub85c\uadf8\uc778 O -&gt; \ub0b4 home \ud0c0\uc784\ub77c\uc778\n      \/\/ Logged in -&gt; My home timeline\n      console.log('&#91;timeline] \ub85c\uadf8\uc778 \uc720\uc800 home \ub85c\ub4dc \/ Login user home load');\n      try {\n <strong>       const homeRes = await fetch(`\/api\/v1\/timelines\/home?limit=20`, { credentials: 'include' });<\/strong>\n\n        const json = await homeRes.json();\n        let arr = Array.isArray(json)? json : json.data || &#91;];\n\n        setTimeline(arr);\n      } catch (e) {\n        console.error(e);\n      }\n    } else {\n      \/\/ \ub85c\uadf8\uc778 X -&gt; URL\uc758 @username \uae00 \ub9cc\n      \/\/ No login -&gt; Only the @username post in the URL\n      console.log('&#91;timeline] \ube44\ub85c\uadf8\uc778\/not log in, param username:', username, '\uae00\ub9cc\/only posts');\n      <strong>const pubRes = await fetch(`\/api\/v1\/timelines\/public?local=true&amp;limit=20`);<\/strong>\n      const json = await pubRes.json();\n      const arr = Array.isArray(json)? json : json.data || &#91;];\n\n      \/\/ @user1 \ud398\uc774\uc9c0\uba74 user1 \uae00\ub9cc \ud544\ud130\n      \/\/ If on the user1 page, filter to show only user1's posts.\n      const filtered = username? arr.filter((p:any) =&gt; p.account?.username === username || p.account?.acct?.startsWith(username)) : arr;\n      console.log('&#91;timeline] \ube44\ub85c\uadf8\uc778 filtered:', filtered.length);\n      <strong>setTimeline(filtered);<\/strong>\n    }\n    setLoading(false);\n  };\n  init();\n}, <strong>&#91;username]);<\/strong><\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \uc804\ub2ec \ubc1b\uc740\ucd08\uae30 \ub370\uc774\ud130 \ud750\ub984 \/ Initial data flow received<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>1.\uc804\ub2ec \ubc1b\uc740 timeline\ub370\uc774\ud130\ub97c \uc544\ub798\uc758 \ud6c5\uc5d0 \ub123\uae30\nPass the received timeline data into the hook below.\n- TimelineList.sx\n\n... ...\n  const {\n    <strong>flatData,<\/strong>\n    fetchNextPage,\n    hasNextPage,\n    isFetchingNextPage,\n  } = useCursorPagination({\n     initialData: <strong>initialTimeline<\/strong>, \/\/ 20\uac1c \ub123\uc74c \/ put in 20\n     fetcher:...\n   })\n\n\n2.useCursorPagination \ud568\uc218 \ub0b4\ubd80\nInside the `useCursorPagination` function\n- app\/hook\/userCursorPagination.tsx\n\n- 2\ucc28\uc6d0 \ubc30\uc5f4\ub85c \ub370\uc774\ud130 page\uc5d0 \uc800\uc7a5\nStore data in a 2D array on the page.\n&#91;&#91;initialData1]&#91;initialData2]... ...]\n\n- \uc774 page \ubc30\uc5f4\ud558\ub098 \ub9c8\ub2e4 20\uac1c\uc529 \ub370\uc774\ud130 \uc800\uc7a5\ub428. \nData for 20 items is stored in each element of this page array.\n\nconst &#91;<strong>pages<\/strong>, setPages] = useState&lt;T&#91;]&#91;]&gt;(initialData.length? <strong>&#91;initialData]<\/strong> : &#91;]);\n\n- flatData\ub85c \ub9ac\ud134 \/ Return as flatData.\n- flat()\ud568\uc218\ub294 2\ucc28\uc6d0 \ubc30\uc5f4\uc744 1\ucc28\uc6d0 \ubc30\uc5f4\ub85c\ub85c \ubcc0\uacbd\ud568(\uadf8\ub0e5 \ub370\uc774\ud130 \ub098\uc5f4)\nThe `flat()` function converts a 2D array into a 1D array (simply listing the data).\n- filter(Boolean)\n fetch\uc2e4\ud328\ub85c null,undefined,false\uac00 \uc788\uc73c\uba74 \uc81c\uac70\n Remove null, undefined, or false values \u200b\u200bresulting from a fetch failure.\n... ...   \n\nconst <strong>flatData<\/strong> = <strong>pages<\/strong>.flat().filter(Boolean) as T&#91;]; \n\n  return {\n    <strong>flatData<\/strong>,\n    pages: pages.map(data =&gt; ({ data })),\n    fetchNextPage,\n    hasNextPage,\n    isFetchingNextPage,\n    isLoading,\n  };\n\n3.UI\uc5d0 \ub370\uc774\ud130 \ud45c\uc2dc \/ Display data on the UI\n- \ub370\uc774\ud130 \uc911\ubcf5 \uc81c\uac70, uniquekey\ub97c \uc704\ud574 \uc778\ub371\uc2a4 \uc0ac\uc6a9\nUsing indexes for data deduplication and unique keys.\n\n... ...\n  const <strong>flat<\/strong> = (<strong>flatData<\/strong> || &#91;]).flat().filter(Boolean) as any&#91;];\n  const <strong>data<\/strong> = flat.length &gt; 0 ? <strong>flat<\/strong> : initialTimeline.filter((p:any) =&gt; p &amp;&amp; p.id);\n... ...\nreturn (\n... ...\n {<strong>data<\/strong>.filter((p:any) =&gt; p &amp;&amp; p.id).map((p: any, idx: number) =&gt; {... ...}\n... ...\n);<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 \ud398\uc774\uc9c0\ub124\uc774\uc158 \/ Pagenation<\/p>\n\n\n\n<p>\u2714\ufe0f \uc2a4\ud06c\ub864 \uac10\uc9c0 \/ Scroll detection<\/p>\n\n\n\n<p>1) \ud398\uc774\uc9c0\ub97c \uc2a4\ud06c\ub864\ud574\uc11c \ub0b4\ub9ac\ub2e4\uac00 \ubb34\ud55c \uc2a4\ud06c\ub864 \ud2b8\ub9ac\uac70 \uc704\uce58\uae4c\uc9c0 30% (threshhold: 0.3)\ub0a8\uc558\uc744\ub54c fetchNextPage()\ud568\uc218 \uc2e4\ud589<br>Execute the <code>fetchNextPage()<\/code> function when scrolling down the page and reaching a point 30% (threshold: 0.3) away from the infinite scroll trigger position.<\/p>\n\n\n\n<p>2)&lt;div ref=<strong>{loaderRef}<\/strong> \uc774\ub807\uac8c \ubb34\ud55c\uc2a4\ud06c\ub864 \uc635\uc800\ubc84\uac00 \ud2b8\ub9ac\uac70\uc758 \uc704\uce58\ub97c \uac10\uc2dc\ud568.<br>With <code>&lt;div ref={loaderRef}&gt;<\/code>, the infinite scroll observer monitors the position of the trigger.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>1.\ubb34\ud55c\uc2a4\ud06c\ub864 \uc635\uc800\ubc84 \/ infinite scroll observer\n\n  const <strong>loaderRef<\/strong> = useRef&lt;HTMLDivElement&gt;(null);\n  useEffect(() =&gt; {\n    const el = loaderRef.current;\n    if (!el ||!hasNextPage) return;\n    const observer = new IntersectionObserver(\n      (&#91;entry]) =&gt; {\n        if (entry.isIntersecting &amp;&amp;!isFetchingNextPage) <strong>fetchNextPage()<\/strong>;\n      },\n      { <strong>threshold: 0.3<\/strong> }\n    );\n    observer.observe(el);\n    return () =&gt; observer.disconnect();\n  }, &#91;hasNextPage, isFetchingNextPage, fetchNextPage]);\n\n2. \ubb34\ud55c \uc2a4\ud06c\ub864 \ud2b8\ub9ac\uac70 \/ Infinite scroll trigger\n\n      &lt;div ref=<strong>{loaderRef}<\/strong> className=\"h-10 flex items-center justify-center text-sm text-&#91;#999]\"&gt;\n        {isFetchingNextPage &amp;&amp; &lt;span&gt;\ubd88\ub7ec\uc624\ub294 \uc911...&lt;\/span&gt;}\n        {!hasNextPage &amp;&amp; data.length &gt; 0 &amp;&amp; &lt;span className=\"text-xs\"&gt;\ub05d \/ No more posts&lt;\/span&gt;}\n      &lt;\/div&gt;\n<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \ub370\uc774\ud130 \ucd94\uac00 \/ Add Data<\/p>\n\n\n\n<p>&#8212; TimelinList.tsx\uc758 fetcher\ucf5c\ubc31\ud568\uc218(\uc2e4\uc81c\ub85c \ub370\uc774\ud130 \ud638\ucd9c\ud558\ub294 \ud568\uc218)\ub97c useCursorPagination\ud568\uc218 \ub0b4\uc5d0\uc11c \uc2e4\ud589<br>Execute the fetcher callback function (the function that actually fetches the data) from TimelinList.tsx within the useCursorPagination function.<\/p>\n\n\n\n<p>&#8212; useCursorPagination\ud568\uc218\ub0b4\uc758 fetchNextPage\ud568\uc218\ub0b4\uc5d0\uc11c \uae30\uc874\ub370\uc774\ud130\uc5d0\uc2e0\uaddc \ub370\uc774\ud130\ub97c\ucd94\uac00<br>Add new data to existing data within the fetchNextPage function inside the useCursorPagination function<\/p>\n\n\n\n<p>&#8212; TimelineList.tsx\uc5d0\uc11c \uc0ac\uc6a9\uac00\ub2a5\ud558\ub3c4\ub85d flatData\ubcc0\uc218\ub85c \ub9ac\ud134,fetchNextPage\ud568\uc218\ub3c4 \uc0ac\uc6a9\uac00\ub2a5\ud558\ub3c4\ub85d \ub9ac\ud134<br>Return the <code>flatData<\/code> variable so it can be used in <code>TimelineList.tsx<\/code>, and also return the <code>fetchNextPage<\/code> function so it is available for use.<\/p>\n\n\n\n<p>1)\ucf5c\ubc31\ud568\uc218 fetcher\uac00 useCursorPagination\ud568\uc218 \ub0b4\uc5d0\uc11c \uc2e4\ud589<br>The callback function <code>fetcher<\/code> is executed within the <code>useCursorPagination<\/code> function.<\/p>\n\n\n\n<p>2)Set{id1, id2, &#8230;}\uc740 \uc911\ubcf5\uc5c6\ub294 \uc9d1\ud569<br>Set{id1, id2, \u2026} is a set containing no duplicates.<\/p>\n\n\n\n<p>3)setPages\ud568\uc218\uc5d0 return [&#8230;prev, filtered]; \ub85c \uae30\uc874\ub370\uc774\ud130\uc5d0 \uc2e0\uaddc \ub370\uc774\ud130 \ucd94\uac00<br>Add new data to the existing data in the <code>setPages<\/code> function using <code>return [...prev, filtered];<\/code>.<\/p>\n\n\n\n<p>4)setPages\ud568\uc218\ub85c \uc800\uc7a5\ub41c pages\uac12\uc744 flatData\ub85c \ub9ac\ud134<br>Returns the <code>pages<\/code> value stored by the <code>setPages<\/code> function as <code>flatData<\/code>.<\/p>\n\n\n\n<p>5)flatData\ub85c \ub9ac\ud134\ub41c \uac12\uc744 <strong> <\/strong> const<strong> flatData<\/strong> = <strong>pages<\/strong>.flat().filter(Boolean) as T[]; \uc774\ub807\uac8c flatData\ubcc0\uc218\uc5d0 \uc800\uc7a5 \ud6c4 \ub9ac\ud134<br>Store the value returned as <code>flatData<\/code> in the <code>flatData<\/code> variable\u2014using <code>const flatData = pages.flat().filter(Boolean) as T[];<\/code>\u2014and then return it.<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code># 1.\ucf5c\ubc31\ud568\uc218 \/ Callback function\n- TimelineList.tsx\n- \uc774 \ucf5c\ubc31\ud568\uc218\uac00 useCursorPagination() \ud6c5 \uc548\uc5d0 fetchNextPage()\uac00 \uc2e4\ud589\ub428.\nThis callback function executes `fetchNextPage()` within the `useCursorPagination()` hook.\n\n  const {\n    flatData,\n    fetchNextPage,\n    hasNextPage,\n    isFetchingNextPage,\n  } = useCursorPagination({\n    \/\/key: &#91;'timeline', tab],\n    key: &#91;'timeline',tab, currentUser || 'anone'], \/\/ add current user\n    initialData: initialTimeline.slice(0,20),  \/\/ \u2705 myapp61\n    fetcher: async (cursor) => { \n... ...\n\n      let url = '';\n      if (tab === 'home') {\n        if (effectiveUser) {\n          url = `\/api\/v1\/timelines\/home?${params.toString()}`;\n        } else {\n          params.set('local', 'true');\n          url = `\/api\/v1\/timelines\/public?${params.toString()}`;\n        }\n      } else if (tab === 'local') {\n        params.set('local', 'true');\n        url = `\/api\/v1\/timelines\/public?${params.toString()}`;\n      } else {\n        url = `\/api\/v1\/timelines\/public?${params.toString()}`;\n      }\n... ...\n<strong> const res = await fetch(url, { credentials: 'include' });<\/strong>\n const arr = Array.isArray(json)? json : (json.data || json.statuses || &#91;]);\n const withMine = arr.map((p:any) => { ... ...  });\n\n       return {\n        <strong>data: withMine,<\/strong>\n        nextCursor: withMine.length? withMine&#91;withMine.length-1].id : null,\n        hasMore: true\n      };\n  }\n\n# 2.fetchNextPage()\ud568\uc218 \/ fetchNextPage() function\n- \uc2e4\uc81c \uc5ec\uae30\uc11c \ucf5c\ubc31\ud568\uc218\uc778 fetcher\ub97c \uc2e4\ud589\ud574\uc11c API\uc5d0\uc11c \uac00\uc838\uc628 \ub370\uc774\ud130\ub97c \uae30\uc874\ub370\uc774\ud130 \ub4a4\uc5d0 \ubd99\uc784\nHere, the `fetcher` callback function is actually executed to append the data retrieved from the API to the existing data.\n\n- hooks\/useCursorPagination.tsx\n\n... ...\nconst &#91;<strong>pages<\/strong>, setPages] = useState&lt;T&#91;]&#91;]>(initialData.length? &#91;initialData] : &#91;]);\n... ...\nconst fetchNextPage = useCallback(async () => {\n... ...\n      const res: any =<strong> await fetcher<\/strong>(nextCursorRef.current || undefined);\n      const data = Array.isArray(res)? res : res.data || &#91;];\n... ...\n      <strong>setPages<\/strong>(prev => {\n        const seen = new Set(prev.flat().map((p:any) => p.id));\n        const filtered = data.filter((p:any) => p.id &amp;&amp;!seen.has(p.id));\n        if (filtered.length === 0) {\n          setHasNextPage(false);\n          return prev;\n        }\n        <strong>return &#91;...prev, filtered];<\/strong>\n      });\n}\n... ...\n\n const<strong> flatData<\/strong> = <strong>pages<\/strong>.flat().filter(Boolean) as T&#91;]; \n\n  return {\n    <strong>flatData<\/strong>,\n    pages: pages.map(data => ({ data })),\n    fetchNextPage,\n    hasNextPage,\n    isFetchingNextPage,\n    isLoading,\n  };\n\n# 3.useCursonpagination() \ud6c5\uc5d0\uc11c \ub9ac\ud134\ub41c flatData\ub97c \ub2e4\uc2dc TimelineList.tsx flatData\uc5d0 \uc800\uc7a5\ud558\uace0 jsx\ub85c \ud45c\uc2dc\nStore the `flatData` returned from the `useCursorPagination()` hook into the `flatData` of `TimelineList.tsx` and render it in JSX.\n\n  const {\n   <strong> flatData<\/strong>,\n    fetchNextPage,\n    hasNextPage,\n    isFetchingNextPage,\n  } = <strong>useCursorPagination(<\/strong>{ ... }\n\n... ...\nreturn (\n... ...\n{data.filter((p:any) => p &amp;&amp; p.id).map((p: any, idx: number) => { ... ... }\n... ...\n);<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\ud83d\udca1 \ucd94\uac00 \ud398\uc774\uc9c0\uac00 \uc788\ub294 \uacbd\uc6b0 \uc11c\ubc84\ub294 \uc544\ub798\uc640 \uac19\uc740 \ud615\uc2dd\uc73c\ub85c \ud638\ucd9c \ub428\nIf there are additional pages, the server is called in the following format\n\n GET \/api\/v1\/timelines\/home?limit=20&amp;max_id=59d38066-6cc2-4c2b-b06e-710f7293fda6\n\n... ...\n\nGET \/api\/v1\/timelines\/home?limit=20&amp;max_id=41b5b137-d56c-4e36-a995-3dbed5ef061c\n\n... ...\n\nGET \/api\/v1\/timelines\/home?limit=20&amp;max_id=a864ab3b-a090-4575-a7b1-0bf5c075f73b<\/code><\/pre>\n\n\n\n<p>\u2714\ufe0f \uae00 50\uac1c \uc0dd\uc131 \ubc0f \uc0ad\uc81c \/ Create and delete 50 posts<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:14px\"><code>\ud83d\udca1\n# 1. \uae00 50\uac1c \uc0dd\uc131 (\ub85c\uadf8\uc778 \uc0c1\ud0dc\uc5d0\uc11c) \/ Generate 50 posts (while logged in)\ncurl -X POST https:\/\/aloy-horizon.duckdns.org\/api\/test\/bulk \\\n  -H \"Content-Type: application\/json\" \\\n  -b \"refresh_token=YOUR_TOKEN\" \\\n  -d '{\"count\":50}'\n\n# 2. \uc0ad\uc81c \/ delete\ncurl -X DELETE https:\/\/aloy-horizon.duckdns.org\/api\/test\/bulk \\\n  -H \"Content-Type: application\/json\" \\\n  -b \"refresh_token=YOUR_TOKEN\" \\<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\ub9c8\ud0dc\ubcf5\uc74c 21\uc7a5 22\uc808 \/ Matthew 21: 22<\/p>\n\n\n\n<p>&#8220;\ub108\ud76c\uac00 \uae30\ub3c4\ud560 \ub54c\uc5d0 \ubb34\uc5c7\uc774\ub4e0\uc9c0 \ubbff\uace0 \uad6c\ud558\ub294 \uac83\uc740 \ub2e4 \ubc1b\uc73c\ub9ac\ub77c \ud558\uc2dc\ub2c8\ub77c&#8221;<\/p>\n\n\n\n<p>&#8220;And everything you ask in prayer, believing, you will receive.&#8221;<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffb \uc774\ubc88\uc5d0\ub294 \ud398\uc774\uc9c0\ub124\uc774\uc158 \uae30\ub2a5\uc758 \uad6c\uc870\ub97c \uc790\uc138\ud788 \uc0b4\ud3b4 \ubd05\uc2dc\ub2e4.Now, let&#8217;s take a closer look at the structure of the pagination feature. \ud83d\udc49\ud83c\udffb \uc774\uc804 \ud3ec\uc2a4\ud2b8\uc5d0\uc11c \ub370\uc774\ud130\uac00 app\/usersui\/[username]\/page.tsx\uc5d0\uc11c \uc2dc\uc791\ud574\uc11c app\/usersui\/[username]\/_components\/themes\/themeex\/Timeline.tsx\uae4c\uc9c0 \uc5b4\ub5bb\uac8c \ud758\ub7ec\uac00\ub294\uc9c0 \uc0b4\ud3b4 \ubcf4\uc558\uc2b5\ub2c8\ub2e4.In the previous post, we examined how data flows from app\/usersui\/[username]\/page.tsx down to app\/usersui\/[username]\/_components\/themes\/themeex\/Timeline.tsx. \ud83d\udc49\ud83c\udffb \uc774 \ud398\uc774\uc9c0\ub124\uc774\uc158 \ud30c\ud2b8\uc5d0\uc11c\ub294 \ucd08\uae30 \ub370\uc774\ud130\uac00 \ud654\uba74\uc5d0 \ud45c\uc2dc\ub41c \ud6c4\uc5d0 \uc2a4\ud06c\ub864\uc744 \ub0b4\ub9ac\uba74 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,27,1,7],"tags":[],"class_list":["post-12149","post","type-post","status-publish","format-standard","hentry","category-news","category-nextjs","category-uncategorized","category-website","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12149","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=12149"}],"version-history":[{"count":70,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12149\/revisions"}],"predecessor-version":[{"id":12226,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/12149\/revisions\/12226"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=12149"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=12149"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=12149"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}