{"id":6984,"date":"2026-07-31T10:15:15","date_gmt":"2026-07-31T01:15:15","guid":{"rendered":"https:\/\/www.freelifemakers.org\/wordpress\/?p=6984"},"modified":"2026-08-01T09:56:26","modified_gmt":"2026-08-01T00:56:26","slug":"nextjs-approute-pageroute","status":"publish","type":"post","link":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/2026\/07\/31\/nextjs-approute-pageroute\/","title":{"rendered":"[nextjs]\uc571\ub77c\uc6b0\ud2b8,\ud398\uc774\uc9c0\ub77c\uc6b0\ud2b8\/App Route,Page Route"},"content":{"rendered":"\n<p>\ud83d\udc49\ud83c\udffbApp Route\uc640 Page Route\ub97c \uc774\ud574\ud558\uae30 \uc704\ud574\uc11c \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5c6\ub294 \uac04\ub2e8\ud55c \ubc29\uba85\ub85d\uc744 \ub9cc\ub4e4\uc5b4 \ubd05\ub2c8\ub2e4.<br>To understand App Routes and Page Routes, we will build a simple guestbook without a database.<\/p>\n\n\n\n<p>\ud83d\udc49\ud83c\udffb \uc785\ub825\ub418\ub294 \uac12\uc740 \ubc30\uc5f4\uc5d0 \uc800\uc7a5\ub429\ub2c8\ub2e4.<br>The input values \u200b\u200bare stored in an array.<\/p>\n\n\n\n<p>\ud83d\udcc1 \ud504\ub85c\uc81d\ud2b8 \uc0dd\uc131<br>Create Project<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx create-next-app@latest<\/code><\/pre>\n\n\n\n<p>\ud83d\udcc1 API \ub9cc\ub4e4\uae30 \/ Creating an API<\/p>\n\n\n\n<p>\u25b7 Next.js\ub294 \ud655\uc7a5\uc790\uac00 .js, .ts, .jsx, .tsx\uc778 \uac83\ub4e4\uc744 \ubaa8\ub450 \ub3d9\uc77c\ud558\uac8c route \ud30c\uc77c\ub85c \uc778\uc2dd\ud569\ub2c8\ub2e4.<br>Next.js treats files with the extensions .js, .ts, .jsx, and .tsx equally as route files.<\/p>\n\n\n\n<p>\u25b7 tsx\ub098 jsx\ub97c \uc0ac\uc6a9\ud574\ub3c4 \ubb38\uc81c\uac00 \uc5c6\uc9c0\ub9cc HTML\uc774\ub098 JSX\ub97c \uc0ac\uc6a9\ud560\ub54c X\uac00 \ubd99\uc2b5\ub2c8\ub2e4.<br>There is no issue with using TSX or JSX, but the &#8220;X&#8221; is included when using HTML or JSX.<\/p>\n\n\n\n<p>\u25b7 JSX\ub294 \uc790\ubc14\uc2a4\ud06c\ub9bd\ud2b8 \uac1d\uccb4\ub97c \ud0dc\uadf8\ud615\uc73c\ub85c \ub9cc\ub4e0 \uac83\uc785\ub2c8\ub2e4.<br>JSX is a tag-like representation of JavaScript objects.<\/p>\n\n\n\n<p>\u25b7 \uc804\uccb4 \ub514\ub809\ud1a0\ub9ac \uad6c\uc870<br>Overall directory structure<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>myapp3\/\n\u251c\u2500\u2500 app\/                        # 1.\uc571\ub77c\uc6b0\ud2b8 \/ App Router\n\u2502   \u251c\u2500\u2500 api\/                    # 1)\ubc31\uc5d4\ub4dc API \/ BackEnd API\n\u2502   \u2502   \u2514\u2500\u2500 guestbookse\/        \n\u2502   \u2502       \u2514\u2500\u2500 route.js        # App Router API : \/api\/guestbookse\n\u2502   \u251c\u2500\u2500 guestbookse\/            # 2)\ud504\ub860\ud2b8 \uc564\ub4dc \/ FrontEnd\n\u2502   \u2502   \u2514\u2500\u2500 page.tsx            # App Router Front: \/guestbookse\n\u2502   \u251c\u2500\u2500 favicon.ico             \n\u2502   \u251c\u2500\u2500 globals.css             \n\u2502   \u251c\u2500\u2500 layout.tsx              \n\u2502   \u2514\u2500\u2500 page.tsx                # \uba54\uc778 \ud648 \/ Main Home: \/\n\u2502\n\u2514\u2500\u2500 pages\/                      # 1.\ud398\uc774\uc9c0\ub77c\uc6b0\ud130 \/ Pages Router\n    \u251c\u2500\u2500 api\/                    \n    \u2502   \u2514\u2500\u2500 guestbook.js        # 1)\ubc31\uc5d4\ub4dc API \/ BackEnd API: \/api\/guestbook\n    \u2514\u2500\u2500 guestbook-page.js       # 2)\ud504\ub860\ud2b8 \uc564\ub4dc \/ FrontEnd: \/guestbook-page\n <\/code><\/pre>\n\n\n\n<p>\u2714\ufe0fApp Route\ubc29\uc2dd(\ucd5c\uc2e0\ubc29\uc2dd)<br>App Router approach (latest method)<\/p>\n\n\n\n<p>&#8212; project\/app \ub514\ub809\ud1a0\ub9ac \uc548\uc5d0 \ub2e4\uc74c \ucc98\ub7fc \ub514\ub809\ud1a0\ub9ac\uc640 \ud30c\uc77c\uc744 \ub9cc\ub4ed\ub2c8\ub2e4.<br>Create the following directories and files inside the <code>project\/app<\/code> directory.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>myapp3\/\n\u2514\u2500\u2500 app\/                        # 1.\uc571\ub77c\uc6b0\ud2b8 \/ App Router\n    \u251c\u2500\u2500 api\/                    # 1)\ubc31\uc5d4\ub4dc API \/ BackEnd API\n    \u2502   \u2514\u2500\u2500 guestbookapp\/        \n    \u2502       \u2514\u2500\u2500 route.js        # App Router API : \/api\/guestbookse\n    \u2514\u2500\u2500 guestbookapp\/            # 2)\ud504\ub860\ud2b8 \uc564\ub4dc \/ FrontEnd\n        \u2514\u2500\u2500 page.tsx            # App Router Front: \/guestbookse<\/code><\/pre>\n\n\n\n<p>&#8212; route.js\ud30c\uc77c\uc5d0 \ub2e4\uc74c \ucf54\ub4dc\ub97c \uc791\uc131\ud569\ub2c8\ub2e4.<br>Write the following code in the route.js file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { NextResponse } from 'next\/server';\n\nconst guestbookData = &#91;\n  { id: 1, name: '2B', content: '\ub2c8\uc5b4\uc624\ud1a0\ub9c8\ud0c0 \/ Nier:Automata' },\n  { id: 2, name: '9S', content: 'Next.js API App Routes.' },\n];\n\n\/\/ GET \uc694\uccad \ucc98\ub9ac (\ub370\uc774\ud130 \uc870\ud68c)\n\/\/ Handle GET requests (data retrieval)\nexport async function GET() {\n  return NextResponse.json(guestbookData);\n}\n\n\/\/ POST \uc694\uccad \ucc98\ub9ac (\ub370\uc774\ud130 \ub4f1\ub85d)\n\/\/ Handle POST requests (data registration)\nexport async function POST(request) {\n  const body = await request.json();\n  const { name, content } = body;\n\n  if (!name || !content) {\n    return NextResponse.json({ message: '\uc774\ub984\uacfc \ub0b4\uc6a9\uc744 \uc785\ub825\ud574\uc8fc\uc138\uc694. \/ Please enter both name and content.' }, { status: 400 });\n  }\n\n  const newPost = {\n    id: Date.now(),\n    name,\n    content,\n  };\n\n  guestbookData.push(newPost);\n  return NextResponse.json(newPost, { status: 201 });\n}\n\n<\/code><\/pre>\n\n\n\n<p>&#8212; \uc11c\ubc84\ub97c \uc2e4\ud589\ud558\uace0 API\ub97c \ud14c\uc2a4\ud2b8\ud569\ub2c8\ub2e4.<br>Run the server and test the API.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \ud130\ubbf8\ub110\uc5d0\uc11c \uc11c\ubc84 \uc2e4\ud589 \/ Run the server in the terminal\nnpm run dev\n\n# \ube0c\ub77c\uc6b0\uc800\uc5d0\uc11c \uc544\ub798 \uc8fc\uc18c\ub85c \uc811\uc18d\ud558\uae30 \/ Access the address below in your browser.\nhttp:&#47;&#47;localhost:3000\/api\/guestbookapp<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"668\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-app-jpg.jpg\" alt=\"\" class=\"wp-image-7044\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-app-jpg.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-app-jpg-300x251.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-app-jpg-768x641.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-app-jpg-400x334.jpg 400w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><figcaption class=\"wp-element-caption\">guestabookapp-App Router<\/figcaption><\/figure>\n\n\n\n<p>&#8212; page.tsx\ud30c\uc77c\uc5d0 \ub2e4\uc74c \ucf54\ub4dc\ub97c \uc791\uc131\ud569\ub2c8\ub2e4.<br>Write the following code in the page.tsx file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\n\/\/ \ubc29\uba85\ub85d \ub370\uc774\ud130\uc758 \ud0c0\uc785 \uc815\uc758\n\/\/ Define the type for guestbook data\ninterface GuestbookItem {\n  id: number;\n  name: string;\n  content: string;\n}\n\nexport default function GuestbookPage() {\n  \n  \/\/ \uc0c1\ud0dc(State) \uc815\uc758\n  \/\/ Define state\n  const &#91;posts, setPosts] = useState&lt;GuestbookItem&#91;]&gt;(&#91;]);\n  const &#91;name, setName] = useState(\"\");\n  const &#91;content, setContent] = useState(\"\");\n  const &#91;isLoading, setIsLoading] = useState(true);\n\n  \/\/ API\uc5d0\uc11c \ubc29\uba85\ub85d \ubaa9\ub85d \uac00\uc838\uc624\ub294 \ud568\uc218 (GET)\n  \/\/ Function to fetch guestbook entries from the API (GET)\n  const fetchPosts = async () =&gt; {\n    try {\n      const response = await fetch(\"\/api\/guestbookapp\");\n      if (!response.ok) throw new Error(\"\ub370\uc774\ud130\ub97c \uac00\uc838\uc624\ub294\ub370 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. \/ Failed to fetch data.\");\n      const data = await response.json();\n      setPosts(data);\n    } catch (error) {\n      console.error(error);\n    } finally {\n      setIsLoading(false);\n    }\n  };\n\n  \/\/ \ud398\uc774\uc9c0\uac00 \ucc98\uc74c \ucf1c\uc9c8 \ub54c API \ud638\ucd9c\ud558\uae30\n  \/\/ Call the API when the page first loads\n  useEffect(() =&gt; {\n    fetchPosts();\n  }, &#91;]);\n\n  \/\/ \uc0c8 \ubc29\uba85\ub85d \ub4f1\ub85d\ud558\ub294 \ud568\uc218 (POST)\n  \/\/ Function to register a new guestbook entry (POST)\n  const handleSubmit = async (e: React.FormEvent) =&gt; {\n    e.preventDefault(); \/\/ \uc0c8\ub85c\uace0\uce68 \ubc29\uc9c0 \/ Prevent page refresh\n\n    if (!name.trim() || !content.trim()) {\n      alert(\"\uc774\ub984\uacfc \ub0b4\uc6a9\uc744 \ubaa8\ub450 \uc785\ub825\ud574 \uc8fc\uc138\uc694.\/Please enter both name and content.\");\n      return;\n    }\n\n    try {\n      const response = await fetch(\"\/api\/guestbookapp\", {\n        method: \"POST\",\n        headers: { \"Content-Type\": \"application\/json\" },\n        body: JSON.stringify({ name, content }),\n      });\n\n      if (response.ok) {\n        \/\/ \ub4f1\ub85d \uc131\uacf5 \uc2dc \uc785\ub825\ucc3d\uc744 \ube44\uc6b0\uace0 \ubaa9\ub85d \uc0c8\ub85c\uace0\uce68\n        \/\/ If registration is successful, clear the input fields and refresh the list\n        setName(\"\");\n        setContent(\"\");\n        fetchPosts();\n      } else {\n        alert(\"\ub4f1\ub85d\uc5d0 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4.\/Failed to register the entry.\");\n      }\n    } catch (error) {\n      console.error(error);\n    }\n  };\n\n  return (\n    &lt;div className=\"p-10 max-w-&#91;600px] mx-auto font-sans\"&gt;\n      &lt;h1 className=\"text-3xl font-bold\"&gt;\ud83d\udcd3 \ubc29\uba85\ub85d \/ Guestbook (App Router)&lt;\/h1&gt;\n\n      {\/* \ubc29\uba85\ub85d \uc785\ub825 \ud3fc \/ Guestbook Entry Form *\/}\n      &lt;form onSubmit={handleSubmit} style={{ display: \"flex\", flexDirection: \"column\", gap: \"10px\", margin: \"20px 0\" }}&gt;\n        &lt;input\n          type=\"text\"\n          placeholder=\"\uc774\ub984\/Name\"\n          value={name}\n          onChange={(e) =&gt; setName(e.target.value)}\n          style={{ padding: \"8px\", border: \"1px solid #ccc\", borderRadius: \"4px\" }}\n        \/&gt;\n        &lt;textarea\n          placeholder=\"\ub0b4\uc6a9\uc744 \uc785\ub825\ud558\uc138\uc694\/Please enter your message\"\n          value={content}\n          onChange={(e) =&gt; setContent(e.target.value)}\n          style={{ padding: \"8px\", border: \"1px solid #ccc\", borderRadius: \"4px\", minHeight: \"8px\" }}\n        \/&gt;\n        &lt;button type=\"submit\" style={{ padding: \"10px\", backgroundColor: \"#dcd809\", color: \"white\", border: \"none\", borderRadius: \"4px\", cursor: \"pointer\" }}&gt;\n          \ub4f1\ub85d\ud558\uae30\/Submit\n        &lt;\/button&gt;\n      &lt;\/form&gt;\n\n      &lt;hr style={{ margin: \"30px 0\", border: \"0\", borderTop: \"1px solid #eee\" }} \/&gt;\n\n      {\/* \ubc29\uba85\ub85d \ubaa9\ub85d \ucd9c\ub825 \/ Guestbook Entry List *\/}\n      &lt;h2 className=\"text-2xl font-bold text-gray-800\"&gt;\ucd5c\uadfc \ubc29\uba85\ub85d \ubaa9\ub85d \/ Recent Guestbook Entries&lt;\/h2&gt;\n      {isLoading ? (\n        &lt;p&gt;\ub85c\ub529 \uc911\/Loading...&lt;\/p&gt;\n      ) : posts.length === 0 ? (\n        &lt;p&gt;\uc791\uc131\ub41c \ubc29\uba85\ub85d\uc774 \uc5c6\uc2b5\ub2c8\ub2e4. \uccab \uae00\uc744 \ub0a8\uaca8\ubcf4\uc138\uc694! \/ There are no guestbook entries yet. Be the first to leave a message!&lt;\/p&gt;\n      ) : (\n        &lt;ul style={{ listStyle: \"none\", padding: 0 }}&gt;\n          {posts.map((post) =&gt; (\n            &lt;li key={post.id} style={{ borderBottom: \"1px solid #eee\", padding: \"15px 0\" }}&gt;\n              &lt;strong&gt;{post.name}&lt;\/strong&gt;\n              &lt;p style={{ margin: \"5px 0 0 0\", color: \"#555\" }}&gt;{post.content}&lt;\/p&gt;\n            &lt;\/li&gt;\n          ))}\n        &lt;\/ul&gt;\n      )}\n    &lt;\/div&gt;\n  );\n}\n\n<\/code><\/pre>\n\n\n\n<p>&#8212; \ube0c\ub77c\uc6b0\uc800\uc5d0 \uc811\uc18d\ud574\uc11c \ubc29\uba85\ub85d\uc744 \ud14c\uc2a4\ud2b8 \ud574\ubd05\ub2c8\ub2e4.<br>Access the browser and test the guestbook.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"776\" height=\"1024\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-AppRouter-jpg-776x1024.jpg\" alt=\"\" class=\"wp-image-7055\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-AppRouter-jpg-776x1024.jpg 776w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-AppRouter-jpg-227x300.jpg 227w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-AppRouter-jpg-768x1014.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-AppRouter-jpg-400x528.jpg 400w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-AppRouter-jpg.jpg 800w\" sizes=\"auto, (max-width: 776px) 100vw, 776px\" \/><figcaption class=\"wp-element-caption\">Screenshot<\/figcaption><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\u2714\ufe0f Page Route\ubc29\uc2dd(\uae30\uc874\ubc29\uc2dd)<br>Page Routing Method (Conventional Method)<\/p>\n\n\n\n<p>&#8212; \ud504\ub85c\uc81d\ud2b8 \ub8e8\ud2b8\uc5d0 pages\uc640 api\ub514\ub809\ud1a0\ub9ac\ub97c \ub9cc\ub4ed\ub2c8\ub2e4.<br>Create <code>pages<\/code> and <code>api<\/code> directories in the project root.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>myapp3\/\n\u2514\u2500\u2500 pages\/                      # 1.\ud398\uc774\uc9c0\ub77c\uc6b0\ud130 \/ Pages Router\n    \u251c\u2500\u2500 api\/                    \n    \u2502   \u2514\u2500\u2500 guestbook.js        # 1)\ubc31\uc5d4\ub4dc API \/ BackEnd API: \/api\/guestbook\n    \u2514\u2500\u2500 guestbook-page.js       # 2)\ud504\ub860\ud2b8 \uc564\ub4dc \/ FrontEnd: \/guestbook-page<\/code><\/pre>\n\n\n\n<p>&#8212; guestbook.js\ud30c\uc77c\uc5d0 \ub2e4\uc74c \ucf54\ub4dc\ub97c \uc791\uc131\ud569\ub2c8\ub2e4.<br>Write the following code in the guestbook.js file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \uc11c\ubc84\uac00 \ucf1c\uc838 \uc788\ub294 \ub3d9\uc548 \uc720\uc9c0\ub418\ub294 \uc784\uc2dc \ub370\uc774\ud130 \uc800\uc7a5\uc18c\n\/\/ Temporary data storage that persists while the server is running\nconst guestbookData = &#91;\n  { id: 1, name: 'Alexios', content: '\uc5b4\uc314\uc52c\ud06c\ub9ac\ub4dc\uc624\ub514\uc138\uc5d0 \/ Assassin\\'s Creed Odyssey' },\n  { id: 2, name: 'Kassandra', content: 'Next.js API Page Routes.' },\n];\n\nexport default function handler(req, res) {\n  \/\/ GET \uc694\uccad \ucc98\ub9ac (\ub370\uc774\ud130 \uc870\ud68c)\n  \/\/ Handle GET requests (data retrieval)\n  if (req.method === 'GET') {\n    return res.status(200).json(guestbookData);\n  }\n\n  \/\/ POST \uc694\uccad \ucc98\ub9ac (\ub370\uc774\ud130 \ub4f1\ub85d)\n  \/\/ Handle POST requests (data registration)\n  if (req.method === 'POST') {\n    const { name, content } = req.body;\n\n    if (!name || !content) {\n      return res.status(400).json({ message: '\uc774\ub984\uacfc \ub0b4\uc6a9\uc744 \uc785\ub825\ud574\uc8fc\uc138\uc694. \/ Please enter both name and content.' });\n    }\n\n    const newPost = {\n      id: Date.now(),\n      name,\n      content,\n    };\n\n    guestbookData.push(newPost);\n    return res.status(201).json(newPost);\n  }\n\n  \/\/ 3. \uc9c0\uc6d0\ud558\uc9c0 \uc54a\ub294 \uba54\uc11c\ub4dc \ucc98\ub9ac\n  \/\/ Handle unsupported methods\n  res.setHeader('Allow', &#91;'GET', 'POST']);\n  return res.status(405).end(`Method ${req.method} Not Allowed`);\n}\n\n<\/code><\/pre>\n\n\n\n<p>&#8212; \uc11c\ubc84\ub97c \uc2e4\ud589\ud558\uace0 API\ub97c \ud14c\uc2a4\ud2b8\ud569\ub2c8\ub2e4.<br>Run the server and test the API.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \ud130\ubbf8\ub110\uc5d0\uc11c \uc11c\ubc84 \uc2e4\ud589 \/ Run the server in the terminal\nnpm run dev\n\n# \ube0c\ub77c\uc6b0\uc800\uc5d0\uc11c \uc544\ub798 \uc8fc\uc18c\ub85c \uc811\uc18d\ud558\uae30 \/ Access the address below in your browser.\nhttp:&#47;&#47;localhost:3000\/api\/guestbookapp\n<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"980\" height=\"782\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-page-page.jpg\" alt=\"\" class=\"wp-image-7051\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-page-page.jpg 980w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-page-page-300x239.jpg 300w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-page-page-768x613.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-page-page-400x319.jpg 400w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/api-page-page-800x638.jpg 800w\" sizes=\"auto, (max-width: 980px) 100vw, 980px\" \/><figcaption class=\"wp-element-caption\">BackEnd-API-Page Router<\/figcaption><\/figure>\n\n\n\n<p>&#8212; guestbook-page.js\ud30c\uc77c\uc5d0 \ub2e4\uc74c \ucf54\ub4dc\ub97c \uc791\uc131\ud569\ub2c8\ub2e4.<br>Write the following code in the guestbook-page.js file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { useEffect, useState } from \"react\";\n\nexport default function GuestbookPage() {\n\n  \/\/ \uc0c1\ud0dc(State) \uc815\uc758\n  \/\/ Define state\n  const &#91;posts, setPosts] = useState(&#91;]);\n  const &#91;name, setName] = useState(\"\");\n  const &#91;content, setContent] = useState(\"\");\n  const &#91;isLoading, setIsLoading] = useState(true);\n\n  \/\/ Pages Router API\uc5d0\uc11c \ub370\uc774\ud130 \uac00\uc838\uc624\uae30 (GET)\n  \/\/ Fetch data from the Pages Router API (GET)\n  const fetchPosts = async () =&gt; {\n    try {\n      \/\/ \ubc29\uae08 \ub9cc\ub4e0 \"pages\/api\/guestbook\" \uc8fc\uc18c\n      \/\/ The address of the newly created \"pages\/api\/guestbook\"\n      const response = await fetch(\"\/api\/guestbook\"); \n      if (!response.ok) throw new Error(\"\ub370\uc774\ud130 \uc218\uc2e0 \uc2e4\ud328 \/ Failed to receive data.\");\n      const data = await response.json();\n      setPosts(data);\n    } catch (error) {\n      console.error(error);\n    } finally {\n      setIsLoading(false);\n    }\n  };\n\n  useEffect(() =&gt; {\n    fetchPosts();\n  }, &#91;]);\n\n  \/\/ \uc0c8 \ubc29\uba85\ub85d \ub4f1\ub85d\ud558\uae30 (POST) \n  \/\/ Register a new guestbook entry\n  const handleSubmit = async (e) =&gt; {\n    e.preventDefault();\n\n    if (!name.trim() || !content.trim()) {\n      alert(\"\uc774\ub984\uacfc \ub0b4\uc6a9\uc744 \uc785\ub825\ud574 \uc8fc\uc138\uc694. \/ Please enter both name and content.\");\n      return;\n    }\n\n    try {\n      const response = await fetch(\"\/api\/guestbook\", {\n        method: \"POST\",\n        headers: { \"Content-Type\": \"application\/json\" },\n        body: JSON.stringify({ name, content }),\n      });\n\n      if (response.ok) {\n        setName(\"\");\n        setContent(\"\");\n        fetchPosts(); \/\/ \ub4f1\ub85d \ud6c4 \ubaa9\ub85d \uc0c8\ub85c\uace0\uce68 \/ Refresh the list after registration\n      } else {\n        alert(\"\ub4f1\ub85d \uc2e4\ud328\");\n      }\n    } catch (error) {\n      console.error(error);\n    }\n  };\n\n  return (\n    &lt;div style={{ padding: \"40px\", maxWidth: \"600px\", margin: \"0 auto\", fontFamily: \"sans-serif\" }}&gt;\n      &lt;h1&gt;\ud83d\udcd3 \ubc29\uba85\ub85d \/ Guestbook (Page Router)&lt;\/h1&gt;\n\n      &lt;form onSubmit={handleSubmit} style={{ display: \"flex\", flexDirection: \"column\", gap: \"10px\", margin: \"20px 0\" }}&gt;\n        &lt;input\n          type=\"text\"\n          placeholder=\"\uc774\ub984\/Name\"\n          value={name}\n          onChange={(e) =&gt; setName(e.target.value)}\n          style={{ padding: \"8px\", border: \"1px solid #ccc\", borderRadius: \"4px\" }}\n        \/&gt;\n        &lt;textarea\n          placeholder=\"\ub0b4\uc6a9\uc744 \uc785\ub825\ud558\uc138\uc694\/Please enter your message\"\n          value={content}\n          onChange={(e) =&gt; setContent(e.target.value)}\n          style={{ padding: \"8px\", border: \"1px solid #ccc\", borderRadius: \"4px\", minHeight: \"60px\" }}\n        \/&gt;\n        &lt;button type=\"submit\" style={{ padding: \"10px\", backgroundColor: \"#40d080\", color: \"white\", border: \"none\", borderRadius: \"4px\", cursor: \"pointer\" }}&gt;\n          \ub4f1\ub85d\ud558\uae30\/Submit\n        &lt;\/button&gt;\n      &lt;\/form&gt;\n\n      &lt;hr style={{ margin: \"30px 0\", border: \"0\", borderTop: \"1px solid #eee\" }} \/&gt;\n\n      &lt;h2 &gt;\ucd5c\uadfc \ubc29\uba85\ub85d \ubaa9\ub85d \/ Recent Guestbook Entries&lt;\/h2&gt;\n      {isLoading ? (\n        &lt;p&gt;\ub85c\ub529 \uc911 \/ Loading...&lt;\/p&gt;\n      ) : (\n        &lt;ul style={{ listStyle: \"none\", padding: 0 }}&gt;\n          {posts.map((post) =&gt; (\n            &lt;li key={post.id} style={{ borderBottom: \"1px solid #eee\", padding: \"15px 0\" }}&gt;\n              &lt;strong&gt;{post.name}&lt;\/strong&gt;\n              &lt;p style={{ margin: \"5px 0 0 0\", color: \"#555\" }}&gt;{post.content}&lt;\/p&gt;\n            &lt;\/li&gt;\n          ))}\n        &lt;\/ul&gt;\n      )}\n    &lt;\/div&gt;\n  );\n}\n\n<\/code><\/pre>\n\n\n\n<p>&#8212; \ube0c\ub77c\uc6b0\uc800\uc5d0 \uc811\uc18d\ud574\uc11c \ubc29\uba85\ub85d\uc744 \ud14c\uc2a4\ud2b8 \ud574\ubd05\ub2c8\ub2e4.<br>Access the browser and test the guestbook.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"916\" height=\"1024\" src=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-PageRouter-jpg-916x1024.jpg\" alt=\"\" class=\"wp-image-7052\" srcset=\"https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-PageRouter-jpg-916x1024.jpg 916w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-PageRouter-jpg-268x300.jpg 268w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-PageRouter-jpg-768x858.jpg 768w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-PageRouter-jpg-400x447.jpg 400w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-PageRouter-jpg-800x894.jpg 800w, https:\/\/www.freelifemakers.org\/wordpress\/wp-content\/uploads\/2026\/07\/front-PageRouter-jpg.jpg 1310w\" sizes=\"auto, (max-width: 916px) 100vw, 916px\" \/><figcaption class=\"wp-element-caption\">FrontEnd &#8211; Page Router<\/figcaption><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\ud83d\udc49\ud83c\udffbApp Route\uc640 Page Route\ub97c \uc774\ud574\ud558\uae30 \uc704\ud574\uc11c \ub370\uc774\ud130\ubca0\uc774\uc2a4 \uc5c6\ub294 \uac04\ub2e8\ud55c \ubc29\uba85\ub85d\uc744 \ub9cc\ub4e4\uc5b4 \ubd05\ub2c8\ub2e4.To understand App Routes and Page Routes, we will build a simple guestbook without a database. \ud83d\udc49\ud83c\udffb \uc785\ub825\ub418\ub294 \uac12\uc740 \ubc30\uc5f4\uc5d0 \uc800\uc7a5\ub429\ub2c8\ub2e4.The input values \u200b\u200bare stored in an array. \ud83d\udcc1 \ud504\ub85c\uc81d\ud2b8 \uc0dd\uc131Create Project \ud83d\udcc1 API \ub9cc\ub4e4\uae30 \/ Creating an API \u25b7 Next.js\ub294 \ud655\uc7a5\uc790\uac00 .js, .ts, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,1,7],"tags":[],"class_list":["post-6984","post","type-post","status-publish","format-standard","hentry","category-nextjs","category-uncategorized","category-website","missing-thumbnail"],"_links":{"self":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/6984","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=6984"}],"version-history":[{"count":75,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/6984\/revisions"}],"predecessor-version":[{"id":7067,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/6984\/revisions\/7067"}],"wp:attachment":[{"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=6984"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=6984"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.freelifemakers.org\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=6984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}