{"id":78,"date":"2026-06-26T13:32:24","date_gmt":"2026-06-26T13:32:24","guid":{"rendered":"https:\/\/aabbee.cafe24.com\/?p=78"},"modified":"2026-06-26T14:02:47","modified_gmt":"2026-06-26T14:02:47","slug":"app-layout","status":"publish","type":"post","link":"https:\/\/coalacoding.com\/?p=78","title":{"rendered":"App.jsx \u2014 \ub808\uc774\uc544\uc6c3 \uad6c\uc131\uacfc \ub370\uc774\ud130 \uac00\uc838\uc624\uae30"},"content":{"rendered":"<blockquote>\n<p><strong>Tip<\/strong>: <strong>Gemini CLI\ub85c \uad6c\ud604\ud558\uae30 \u2014 App.jsx \ub808\uc774\uc544\uc6c3 &amp; \ub370\uc774\ud130 \ub85c\ub529<\/strong><\/p>\n<ul>\n<li><strong>\ud504\ub86c\ud504\ud2b8:<\/strong> <code>gemini &quot;src\/App.jsx\ub97c \uc791\uc131\ud574\uc918. TMDB API\uc5d0\uc11c movie\/now_playing, tv\/airing_today, movie\/top_rated \ub370\uc774\ud130\ub97c Promise.all\ub85c \ub3d9\uc2dc\uc5d0 \uac00\uc838\uc640\uc57c \ud574. useState\ub85c 3\uac1c\uc758 \uc0c1\ud0dc\ub97c \uad00\ub9ac\ud558\uace0, useEffect\ub85c \uc571 \uc2dc\uc791 \uc2dc \ud55c \ubc88\ub9cc \ud638\ucd9c\ud574\uc918. \uac00\uc838\uc628 \ub370\uc774\ud130\ub294 Outlet\uc758 context\ub85c \ud558\uc704 \ud398\uc774\uc9c0\uc5d0 \uc804\ub2ec\ud558\uace0, Header\uc640 Footer\ub3c4 \ud3ec\ud568\ud574\uc918. axios \uc778\uc2a4\ud134\uc2a4\ub294 [axios \uc778\uc2a4\ud134\uc2a4 \uacbd\ub85c]\uc5d0\uc11c \uac00\uc838\uc640\uc918.&quot;<\/code>\n<ul>\n<li><strong>\uc0ac\uc6a9 \uac00\uc774\ub4dc:<\/strong> <code>[axios \uc778\uc2a4\ud134\uc2a4 \uacbd\ub85c]<\/code>\ub97c <code>.\/api\/axios<\/code>\ub85c \ubc14\uafbc\ub2e4. API \uc5d4\ub4dc\ud3ec\uc778\ud2b8\uac00 \ub2e4\ub974\uba74 <code>tv\/airing_today<\/code> \ubd80\ubd84\uc744 \uc218\uc815\ud55c\ub2e4.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/blockquote>\n<h2>1. App.jsx\uc758 \uc5ed\ud560<\/h2>\n<p><code>App.jsx<\/code>\ub294 GOFLEX \uc571\uc758 <strong>\ubf08\ub300<\/strong> \uc5ed\ud560\uc744 \ud55c\ub2e4. \uc774 \ud30c\uc77c\uc774 \ub2f4\ub2f9\ud558\ub294 \uc77c\uc740 \uc138 \uac00\uc9c0\uc774\ub2e4.<\/p>\n<ul>\n<li>TMDB API\uc5d0\uc11c \uc601\ud654 \ub370\uc774\ud130 3\uc885(\ud604\uc7ac \uc0c1\uc601, \uc778\uae30, \ucd5c\uace0 \ud3c9\uc810)\uc744 \uac00\uc838\uc628\ub2e4<\/li>\n<li>\uc0c1\ub2e8\uc5d0 <code>Header<\/code>, \ud558\ub2e8\uc5d0 <code>Footer<\/code>\ub97c \ubc30\uce58\ud55c\ub2e4<\/li>\n<li>\ud558\uc704 \ud398\uc774\uc9c0\uac00 \ub80c\ub354\ub9c1\ub418\ub294 <code>Outlet<\/code>\uc5d0 \ub370\uc774\ud130\ub97c \uc804\ub2ec\ud55c\ub2e4<\/li>\n<\/ul>\n<table>\n<thead>\n<tr>\n<th align=\"left\">\uc21c\uc11c<\/th>\n<th align=\"left\">\ub9cc\ub4e4 \uae30\ub2a5<\/th>\n<th align=\"left\">\ud575\uc2ec \uac1c\ub150<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td align=\"left\">1\ub2e8\uacc4<\/td>\n<td align=\"left\">import + \uc0c1\ud0dc \ubcc0\uc218<\/td>\n<td align=\"left\"><code>useState<\/code><\/td>\n<\/tr>\n<tr>\n<td align=\"left\">2\ub2e8\uacc4<\/td>\n<td align=\"left\">API \ub370\uc774\ud130 \ub85c\ub529<\/td>\n<td align=\"left\"><code>Promise.all<\/code> + <code>useEffect<\/code><\/td>\n<\/tr>\n<tr>\n<td align=\"left\">3\ub2e8\uacc4<\/td>\n<td align=\"left\">\ud654\uba74 \ub80c\ub354\ub9c1<\/td>\n<td align=\"left\"><code>Outlet context<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<hr>\n<h2>2. 1\ub2e8\uacc4 \u2014 import + \uc0c1\ud0dc \ubcc0\uc218<\/h2>\n<p><code>src\/App.jsx<\/code> \ud30c\uc77c\uc744 \uc5f4\uace0 \uc784\uc2dc \ucf54\ub4dc\ub97c <strong>\ubaa8\ub450 \uc9c0\uc6b4 \ub4a4<\/strong> \uc544\ub798\ub97c \uc791\uc131\ud55c\ub2e4.<\/p>\n<pre><code class=\"language-jsx\">import { useState, useEffect } from &quot;react&quot;;\nimport { Outlet } from &quot;react-router&quot;;\nimport { Header } from &quot;.\/components\/Header.jsx&quot;;\nimport { Footer } from &quot;.\/components\/Footer.jsx&quot;;\nimport api from &quot;.\/api\/axios&quot;;\n\nexport default function App() {\n  const [now, setNow] = useState(null);\n  const [popular, setPopular] = useState(null);\n  const [topRated, setTopRated] = useState(null);\n<\/code><\/pre>\n<table>\n<thead>\n<tr>\n<th align=\"left\">\uc904<\/th>\n<th align=\"left\">\uc124\uba85<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td align=\"left\">1<\/td>\n<td align=\"left\"><code>useState<\/code>(\uc720\uc988\uc2a4\ud14c\uc774\ud2b8)\uc640 <code>useEffect<\/code>(\uc720\uc988\uc774\ud399\ud2b8) \u2014 React\uc758 Hook(\ud6c5)\uc774\ub2e4. \ud6c5\uc740 \ucef4\ud3ec\ub10c\ud2b8\uc5d0 \ud2b9\ubcc4\ud55c \ub2a5\ub825\uc744 \ubd80\uc5ec\ud558\ub294 \ub3c4\uad6c\uc774\ub2e4. <code>useState<\/code>\ub294 \ucef4\ud3ec\ub10c\ud2b8 \ub0b4\ubd80\uc5d0 \uc0c1\ud0dc \uac12\uc744 \uc800\uc7a5\ud558\uace0, \uac12\uc774 \ubc14\ub00c\uba74 \ud654\uba74\uc744 \uc790\ub3d9\uc73c\ub85c \ub2e4\uc2dc \ub80c\ub354\ub9c1\ud558\ub294 \ud6c5\uc774\ub2e4. <code>useEffect<\/code>\ub294 \ucef4\ud3ec\ub10c\ud2b8\uc5d0\uc11c \ud568\uc218\uc758 \uc2e4\ud589 \uc2dc\uc810\uc744 \uc81c\uc5b4\ud558\ub294 \ud6c5\uc774\ub2e4.<\/td>\n<\/tr>\n<tr>\n<td align=\"left\">2<\/td>\n<td align=\"left\"><code>Outlet<\/code>(\uc544\uc6b8\ub81b) \u2014 \ub9ac\uc561\ud2b8 \ub77c\uc6b0\ud130\uc758 children path(\ud328\uc2a4)\ub85c \uc5f0\uacb0\ub41c \ucef4\ud3ec\ub10c\ud2b8\ub97c \ub80c\ub354\ub9c1(\ub80c\ub354\ub9c1)\ud574\uc900\ub2e4.<\/td>\n<\/tr>\n<tr>\n<td align=\"left\">3-4<\/td>\n<td align=\"left\"><code>Header<\/code>\uc640 <code>Footer<\/code>\ub97c \ubcc4\ub3c4 \ud30c\uc77c\uc5d0\uc11c \uac00\uc838\uc628\ub2e4. \ub2e4\uc74c \ud3b8\uc5d0\uc11c \ub9cc\ub4e0\ub2e4.<\/td>\n<\/tr>\n<tr>\n<td align=\"left\">5<\/td>\n<td align=\"left\">3\ud3b8\uc5d0\uc11c \ub9cc\ub4e0 TMDB API \uc778\uc2a4\ud134\uc2a4\ub97c \uac00\uc838\uc628\ub2e4.<\/td>\n<\/tr>\n<tr>\n<td align=\"left\">8-10<\/td>\n<td align=\"left\">\uc601\ud654 \ub370\uc774\ud130\ub97c \ub2f4\uc744 \uc0c1\ud0dc \ubcc0\uc218 3\uac1c(<code>now<\/code>, <code>popular<\/code>, <code>topRated<\/code>)\ub97c \uc120\uc5b8\ud55c\ub2e4. \ucd08\uae30\uac12\uc740 \ubaa8\ub450 <code>null<\/code>(\uc544\uc9c1 \uc544\ubb34\uac83\ub3c4 \uc5c6\uc74c)\uc774\ub2e4.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><Accordion title=\"\ucd08\uae30\uac12 null vs [] \ucc28\uc774\"><br \/>\n| \ucd08\uae30\uac12 | \uc758\ubbf8                                                             |<br \/>\n| :&#8212;&#8211; | :&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; |<br \/>\n| `null` | \uc544\uc9c1 API\ub97c \ud638\ucd9c\ud558\uc9c0 \uc54a\uc740 \uc0c1\ud0dc\uc774\ub2e4. \ub85c\ub529 \uc911\uc774\ub77c\uace0 \ud310\ub2e8\ud560 \uc218 \uc788\ub2e4. |<br \/>\n| `[]`   | API\ub97c \ud638\ucd9c\ud588\uc9c0\ub9cc \uacb0\uacfc\uac00 0\uac74\uc778 \uc0c1\ud0dc\uc774\ub2e4.                          |<\/p>\n<p><code>null<\/code>\uc774\uba74 \ub85c\ub529 \uc2a4\ud53c\ub108\ub97c \ud45c\uc2dc\ud558\uace0, <code>[]<\/code>\uc774\uba74 &quot;\uacb0\uacfc \uc5c6\uc74c&quot;\uc744 \ud45c\uc2dc\ud558\ub294 \uc2dd\uc73c\ub85c \uad6c\ubd84\ud560 \uc218 \uc788\ub2e4.<br \/>\n<\/Accordion><\/p>\n<hr>\n<h2>3. 2\ub2e8\uacc4 \u2014 API \ub370\uc774\ud130 \ub85c\ub529<\/h2>\n<p>\uac19\uc740 <code>App.jsx<\/code> \ud30c\uc77c\uc5d0\uc11c, <code>const [topRated, ...<\/code> \uc904 \ubc14\ub85c \uc544\ub798\uc5d0 \uc774\uc5b4\uc11c \uc791\uc131\ud55c\ub2e4. \uc774 \ucf54\ub4dc\ub294 \uc571\uc774 \ucc98\uc74c \uc2e4\ud589\ub420 \ub54c TMDB \uc11c\ubc84\uc5d0 &quot;\ud604\uc7ac \uc0c1\uc601\uc791, \uc778\uae30\uc791, \ucd5c\uace0 \ud3c9\uc810 \uc601\ud654\ub97c \ud55c\uaebc\ubc88\uc5d0 \ubcf4\ub0b4\uc918&quot;\ub77c\uace0 \uc694\uccad\ud558\ub294 \ubd80\ubd84\uc774\ub2e4.<\/p>\n<pre><code class=\"language-jsx\">  async function loadMovie() {\n    const [res1, res2, res3] = await Promise.all([\n      api.get(&quot;movie\/now_playing&quot;),\n      api.get(&quot;tv\/airing_today&quot;),\n      \/\/api.get(&quot;movie\/popular&quot;),\n      api.get(&quot;movie\/top_rated&quot;),\n    ]);\n    setNow(res1.data.results.filter((m) =&gt; m.poster_path));\n    setPopular(res2.data.results.filter((m) =&gt; m.poster_path));\n    setTopRated(res3.data.results.filter((m) =&gt; m.poster_path));\n  }\n\n  useEffect(() =&gt; {\n    loadMovie();\n  }, []);\n<\/code><\/pre>\n<h4>Promise.all \uc124\uba85<\/h4>\n<pre><code class=\"language-jsx\">const [res1, res2, res3] = await Promise.all([\n  api.get(&quot;movie\/now_playing&quot;),\n  api.get(&quot;movie\/popular&quot;),\n  api.get(&quot;movie\/top_rated&quot;),\n]);\n<\/code><\/pre>\n<p><code>Promise.all<\/code>(\ud504\ub85c\ubbf8\uc2a4 \uc62c)\uc740 \uc5ec\ub7ec API \uc694\uccad\uc744 <strong>\ub3d9\uc2dc\uc5d0<\/strong> \ubcf4\ub0b4\uace0, \ubaa8\ub450 \ub05d\ub098\uba74 \uacb0\uacfc\ub97c \ud55c\uaebc\ubc88\uc5d0 \ubc1b\ub294\ub2e4.<\/p>\n<table>\n<thead>\n<tr>\n<th align=\"left\">\ubc29\uc2dd<\/th>\n<th align=\"left\">\uc694\uccad \uc2dc\uac04<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td align=\"left\">\uc21c\ucc28 \uc2e4\ud589 (<code>await<\/code> 3\ubc88)<\/td>\n<td align=\"left\">1\ucd08 + 1\ucd08 + 1\ucd08 = <strong>3\ucd08<\/strong><\/td>\n<\/tr>\n<tr>\n<td align=\"left\"><code>Promise.all<\/code><\/td>\n<td align=\"left\">\uac00\uc7a5 \ub290\ub9b0 1\uac1c \uae30\uc900 = <strong>\uc57d 1\ucd08<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\uc694\uccad 3\uac1c\ub97c \uc21c\uc11c\ub300\ub85c \ubcf4\ub0b4\uba74 \uac01\uac01\uc758 \uc751\ub2f5\uc744 \uae30\ub2e4\ub824\uc57c \ud558\uc9c0\ub9cc, <code>Promise.all<\/code>\ub85c \ub3d9\uc2dc\uc5d0 \ubcf4\ub0b4\uba74 \ubaa8\ub450 \ub05d\ub0a0 \ub54c\uae4c\uc9c0 \ud55c \ubc88\ub9cc \uae30\ub2e4\ub9ac\uba74 \ub41c\ub2e4.<\/p>\n<h4>filter \uc124\uba85<\/h4>\n<pre><code class=\"language-jsx\">setNow(res1.data.results.filter((m) =&gt; m.poster_path));\n<\/code><\/pre>\n<p><code>.filter()<\/code>\ub85c \ud3ec\uc2a4\ud130 \uc774\ubbf8\uc9c0(<code>poster_path<\/code>)\uac00 \uc788\ub294 \uc601\ud654\ub9cc \uace8\ub77c\ub0b8\ub2e4. \ud3ec\uc2a4\ud130\uac00 \uc5c6\uc73c\uba74 \ud654\uba74\uc5d0 \ube48 \uce74\ub4dc\uac00 \uc0dd\uae30\uae30 \ub54c\ubb38\uc774\ub2e4.<\/p>\n<p><Accordion title=\"useEffect\uc758 \ube48 \ubc30\uc5f4 []\uc740 \ubb34\uc2a8 \ub73b\uc778\uac00?\"><br \/>\n| \uc758\uc874\uc131 \ubc30\uc5f4    | \uc2e4\ud589 \uc2dc\uc810                                  |<br \/>\n| :&#8212;&#8212;&#8212;&#8212;- | :&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; |<br \/>\n| `[]` (\ube48 \ubc30\uc5f4) | \ucef4\ud3ec\ub10c\ud2b8\uac00 \ucc98\uc74c \ud654\uba74\uc5d0 \ub098\ud0c0\ub0a0 \ub54c <strong>1\ubc88\ub9cc<\/strong> |<br \/>\n| `[id]`         | `id` \uac12\uc774 \ubc14\ub014 \ub54c\ub9c8\ub2e4 <strong>\ub9e4\ubc88<\/strong>             |<br \/>\n| \uc5c6\uc74c (\uc0dd\ub7b5)    | \ucef4\ud3ec\ub10c\ud2b8\uac00 \ub80c\ub354\ub9c1\ub420 \ub54c <strong>\ub9e4\ubc88<\/strong> (\ube44\ucd94\ucc9c)   |<br \/>\n<\/Accordion><\/p>\n<hr>\n<h2>4. 3\ub2e8\uacc4 \u2014 \ud654\uba74 \ub80c\ub354\ub9c1<\/h2>\n<p>\uac19\uc740 <code>App.jsx<\/code> \ud30c\uc77c\uc5d0\uc11c, <code>useEffect<\/code> \ube14\ub85d \ubc14\ub85c \uc544\ub798\uc5d0 \uc774\uc5b4\uc11c \uc791\uc131\ud55c\ub2e4. \uc774 \ubd80\ubd84\uc740 &quot;\ub370\uc774\ud130\uac00 \uc544\uc9c1 \ub3c4\ucc29\ud558\uc9c0 \uc54a\uc558\ub294\uc9c0 \ud655\uc778\ud558\uace0, \ub3c4\ucc29\ud55c \ub370\uc774\ud130\ub97c \ud558\uc704 \ud398\uc774\uc9c0\uc5d0 <strong>\ud0dd\ubc30\ucc98\ub7fc \ubcf4\ub0b4\uc8fc\ub294<\/strong>&quot; \uc5ed\ud560\uc774\ub2e4. <code>&lt;&gt;<\/code>(Fragment, \ud504\ub798\uadf8\uba3c\ud2b8)\ub294 \uc5ec\ub7ec \uc694\uc18c\ub97c \uac10\uc2f8\ub418 \uc2e4\uc81c HTML \ud0dc\uadf8\ub97c \ucd94\uac00\ud558\uc9c0 \uc54a\ub294 \ud22c\uba85 \ud3ec\uc7a5\uc9c0\uc774\ub2e4.<\/p>\n<pre><code class=\"language-jsx\">  const loading = now === null || popular === null || topRated === null;\n  const ctx = {\n    now: now || [],\n    popular: popular || [],\n    topRated: topRated || [],\n    loading,\n  };\n\n  return (\n    &lt;&gt;\n      &lt;Header \/&gt;\n      &lt;Outlet context={ctx} \/&gt;\n      &lt;Footer \/&gt;\n    &lt;\/&gt;\n  );\n}\n<\/code><\/pre>\n<table>\n<thead>\n<tr>\n<th align=\"left\">\uc904<\/th>\n<th align=\"left\">\uc124\uba85<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td align=\"left\">1<\/td>\n<td align=\"left\">\uc138 \uc0c1\ud0dc \uc911 \ud558\ub098\ub77c\ub3c4 <code>null<\/code>\uc774\uba74 \uc544\uc9c1 \ub85c\ub529 \uc911\uc774\ub2e4.<\/td>\n<\/tr>\n<tr>\n<td align=\"left\">2-7<\/td>\n<td align=\"left\"><code>ctx<\/code> \uac1d\uccb4\uc5d0 \uc601\ud654 \ub370\uc774\ud130 3\uc885\uacfc <code>loading<\/code> \uc0c1\ud0dc\ub97c \ub2f4\ub294\ub2e4. <code>&amp;#124;&amp;#124;<\/code>(OR \uc5f0\uc0b0\uc790)\ub294 \uc67c\ucabd \uac12\uc774 <code>null<\/code>, <code>undefined<\/code>, <code>0<\/code> \ub4f1 \uac70\uc9d3\uc73c\ub85c \ud310\ub2e8\ub418\ub294 \uac12\uc77c \ub54c \uc624\ub978\ucabd \uac12\uc744 \ubc18\ud658\ud55c\ub2e4. <code>now<\/code>\uac00 \uc544\uc9c1 <code>null<\/code>\uc774\uba74 <code>[]<\/code>\ub97c \ubc18\ud658\ud558\ubbc0\ub85c \ud558\uc704 \ucef4\ud3ec\ub10c\ud2b8\uac00 \ube48 \ubc30\uc5f4\uc744 \uc548\uc804\ud558\uac8c \ubc1b\uc744 \uc218 \uc788\ub2e4.<\/td>\n<\/tr>\n<tr>\n<td align=\"left\">11<\/td>\n<td align=\"left\"><code>Header<\/code> \ucef4\ud3ec\ub10c\ud2b8\ub97c \uc0c1\ub2e8\uc5d0 \ubc30\uce58\ud55c\ub2e4.<\/td>\n<\/tr>\n<tr>\n<td align=\"left\">12<\/td>\n<td align=\"left\"><code>Outlet<\/code>\uc758 <code>context<\/code>\uc5d0 <code>ctx<\/code> \uac1d\uccb4\ub97c \uc804\ub2ec\ud55c\ub2e4. \ud558\uc704 \ud398\uc774\uc9c0(<code>Home<\/code>, <code>MovieDetail<\/code> \ub4f1)\uc5d0\uc11c \uc774 \ub370\uc774\ud130\ub97c \ubc1b\uc544\uc11c \uc0ac\uc6a9\ud55c\ub2e4.<\/td>\n<\/tr>\n<tr>\n<td align=\"left\">13<\/td>\n<td align=\"left\"><code>Footer<\/code> \ucef4\ud3ec\ub10c\ud2b8\ub97c \ud558\ub2e8\uc5d0 \ubc30\uce58\ud55c\ub2e4.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><Accordion title=\"Outlet\uc758 context\ub294 \uc5b4\ub5bb\uac8c \ubc1b\ub098?\"><br \/>\n\ud558\uc704 \ucef4\ud3ec\ub10c\ud2b8\uc5d0\uc11c `useOutletContext()` \ud6c5\uc73c\ub85c \uaebc\ub0b8\ub2e4.<\/p>\n<pre><code class=\"language-jsx\">\/\/ Home.jsx\uc5d0\uc11c (7\ud3b8\uc5d0\uc11c \uc791\uc131)\nimport { useOutletContext } from &quot;react-router&quot;;\n\nexport function Home() {\n  const { now, popular, topRated, loading } = useOutletContext();\n}\n<\/code><\/pre>\n<p><\/Accordion><Accordion title=\"Header.jsx \/ Footer.jsx \uc784\uc2dc \ud30c\uc77c\"><br \/>\n\uc544\uc9c1 \ub9cc\ub4e4\uc9c0 \uc54a\uc558\uc73c\ubbc0\ub85c \uc5d0\ub7ec\ub97c \ubc29\uc9c0\ud558\uae30 \uc704\ud574 \ube48 \ud30c\uc77c\uc744 \ub9cc\ub4e4\uc5b4 \ub454\ub2e4.<\/p>\n<pre><code class=\"language-jsx\">export function Header() {\n  return &lt;header&gt;\ud5e4\ub354 (\uc900\ube44\uc911)&lt;\/header&gt;;\n}\n<\/code><\/pre>\n<pre><code class=\"language-jsx\">export function Footer() {\n  return &lt;footer&gt;\ud478\ud130 (\uc900\ube44\uc911)&lt;\/footer&gt;;\n}\n<\/code><\/pre>\n<p><\/Accordion><\/p>\n<hr>\n<h2>5. \uc804\uccb4 \ucf54\ub4dc<\/h2>\n<pre><code class=\"language-jsx\">import { useState, useEffect } from &quot;react&quot;;\nimport { Outlet } from &quot;react-router&quot;;\nimport { Header } from &quot;.\/components\/Header.jsx&quot;;\nimport { Footer } from &quot;.\/components\/Footer.jsx&quot;;\nimport api from &quot;.\/api\/axios&quot;;\n\nexport default function App() {\n  const [now, setNow] = useState(null);\n  const [popular, setPopular] = useState(null);\n  const [topRated, setTopRated] = useState(null);\n\n  async function loadMovie() {\n    const [res1, res2, res3] = await Promise.all([\n      api.get(&quot;movie\/now_playing&quot;),\n      api.get(&quot;tv\/popular&quot;),\n      api.get(&quot;movie\/top_rated&quot;),\n    ]);\n    setNow(res1.data.results.filter((m) =&gt; m.poster_path));\n    setPopular(res2.data.results.filter((m) =&gt; m.poster_path));\n    setTopRated(res3.data.results.filter((m) =&gt; m.poster_path));\n  }\n\n  useEffect(() =&gt; {\n    loadMovie();\n  }, []);\n\n  const loading = now === null || popular === null || topRated === null;\n  const ctx = {\n    now: now || [],\n    popular: popular || [],\n    topRated: topRated || [],\n    loading,\n  };\n\n  return (\n    &lt;&gt;\n      &lt;Header \/&gt;\n      &lt;Outlet context={ctx} \/&gt;\n      &lt;Footer \/&gt;\n    &lt;\/&gt;\n  );\n}\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Tip: Gemini CLI\ub85c \uad6c\ud604\ud558\uae30 \u2014 App.jsx \ub808\uc774\uc544\uc6c3 &amp; \ub370\uc774\ud130 \ub85c\ub529 \ud504\ub86c\ud504\ud2b8: gemini &quot;src\/App.jsx\ub97c \uc791\uc131\ud574\uc918. TMDB API\uc5d0\uc11c movie\/now_playing, tv\/airing_today, movie\/top_rated \ub370\uc774\ud130\ub97c Promise.all\ub85c \ub3d9\uc2dc\uc5d0 \uac00\uc838\uc640\uc57c \ud574. useState\ub85c 3\uac1c\uc758 \uc0c1\ud0dc\ub97c \uad00\ub9ac\ud558\uace0, useEffect\ub85c \uc571 \uc2dc\uc791 \uc2dc \ud55c \ubc88\ub9cc \ud638\ucd9c\ud574\uc918. \uac00\uc838\uc628 \ub370\uc774\ud130\ub294 Outlet\uc758 context\ub85c \ud558\uc704 \ud398\uc774\uc9c0\uc5d0 \uc804\ub2ec\ud558\uace0, Header\uc640 Footer\ub3c4 \ud3ec\ud568\ud574\uc918. axios \uc778\uc2a4\ud134\uc2a4\ub294 [axios \uc778\uc2a4\ud134\uc2a4 \uacbd\ub85c]\uc5d0\uc11c \uac00\uc838\uc640\uc918.&quot; \uc0ac\uc6a9 \uac00\uc774\ub4dc: [axios \uc778\uc2a4\ud134\uc2a4 &#8230; <a title=\"App.jsx \u2014 \ub808\uc774\uc544\uc6c3 \uad6c\uc131\uacfc \ub370\uc774\ud130 \uac00\uc838\uc624\uae30\" class=\"read-more\" href=\"https:\/\/coalacoding.com\/?p=78\" aria-label=\"App.jsx \u2014 \ub808\uc774\uc544\uc6c3 \uad6c\uc131\uacfc \ub370\uc774\ud130 \uac00\uc838\uc624\uae30\uc5d0 \ub300\ud574 \ub354 \uc790\uc138\ud788 \uc54c\uc544\ubcf4\uc138\uc694\">\ub354 \uc77d\uae30<\/a><\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[],"class_list":["post-78","post","type-post","status-publish","format-standard","hentry","category-react-movie-app"],"_links":{"self":[{"href":"https:\/\/coalacoding.com\/index.php?rest_route=\/wp\/v2\/posts\/78","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/coalacoding.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/coalacoding.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/coalacoding.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=78"}],"version-history":[{"count":1,"href":"https:\/\/coalacoding.com\/index.php?rest_route=\/wp\/v2\/posts\/78\/revisions"}],"predecessor-version":[{"id":2255,"href":"https:\/\/coalacoding.com\/index.php?rest_route=\/wp\/v2\/posts\/78\/revisions\/2255"}],"wp:attachment":[{"href":"https:\/\/coalacoding.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=78"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/coalacoding.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=78"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/coalacoding.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=78"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}