|
| 1 | +--- |
| 2 | +sidebar_position: 3 |
| 3 | +--- |
| 4 | + |
| 5 | +# Page layouts |
| 6 | + |
| 7 | +์ด ๊ฐ์ด๋๋ ์ฌ๋ฌ ํ์ด์ง๊ฐ ๊ฐ์ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ๊ณต์ ํ๊ณ , ์ฃผ์ ๋ด์ฉ๋ง ๋ค๋ฅธ ๊ฒฝ์ฐ ์ฌ์ฉํ ์ ์๋ _ํ์ด์ง ๋ ์ด์์_ ์ ๋ํด ์ค๋ช
ํฉ๋๋ค. |
| 8 | + |
| 9 | +:::info |
| 10 | + |
| 11 | +์ด ๊ฐ์ด๋์์ ๋ค๋ฃจ์ง ์๋ ์ง๋ฌธ์ด ์์ผ์ ๊ฐ์? ์ค๋ฅธ์ชฝ ํ๋์ ๋ฒํผ์ ๋๋ฌ ํผ๋๋ฐฑ์ ๋จ๊ฒจ์ฃผ์ธ์. ์ฌ๋ฌ๋ถ์ ์๊ฒฌ์ ๋ฐ์ํด ๊ฐ์ด๋๋ฅผ ํ์ฅํด ๋๊ฐ๊ฒ ์ต๋๋ค! |
| 12 | + |
| 13 | +::: |
| 14 | + |
| 15 | +## ๊ฐ๋จํ ๋ ์ด์์ |
| 16 | + |
| 17 | +๊ฐ๋จํ ๋ ์ด์์ ์์๋ก ์ค๋ช
ํด ๋ณด๊ฒ ์ต๋๋ค. ์ด ํ์ด์ง๋ ์ฌ์ดํธ ๋ด๋น๊ฒ์ด์
์ด ํฌํจ๋ ํค๋, ๋ ๊ฐ์ ์ฌ์ด๋๋ฐ, ์ธ๋ถ ๋งํฌ๊ฐ ํฌํจ๋ ํธํฐ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค. ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์ ์์ผ๋ฉฐ, ๋์ ์ธ ๋ถ๋ถ์ ์ฌ์ด๋๋ฐ์ ํค๋ ์ค๋ฅธ์ชฝ์ ์๋ ํ
๋ง ์ ํ ๋ฒํผ๋ฟ์
๋๋ค. ์ด๋ฌํ ๋ ์ด์์์ shared/ui ๋๋ app/layouts์ ํฌํจ์ํฌ ์ ์์ผ๋ฉฐ, props๋ฅผ ํตํด ์ ๋ฌ๋ฐ์ ์ฌ์ด๋๋ฐ ์ฝํ
์ธ ๋ฅผ ํ์ํฉ๋๋ค. |
| 18 | + |
| 19 | +```tsx title="shared/ui/layout/Layout.tsx" |
| 20 | +import { Link, Outlet } from "react-router-dom"; |
| 21 | +import { useThemeSwitcher } from "./useThemeSwitcher"; |
| 22 | + |
| 23 | +export function Layout({ siblingPages, headings }) { |
| 24 | + const [theme, toggleTheme] = useThemeSwitcher(); |
| 25 | + |
| 26 | + return ( |
| 27 | + <div> |
| 28 | + <header> |
| 29 | + <nav> |
| 30 | + <ul> |
| 31 | + <li> <Link to="/">Home</Link> </li> |
| 32 | + <li> <Link to="/docs">Docs</Link> </li> |
| 33 | + <li> <Link to="/blog">Blog</Link> </li> |
| 34 | + </ul> |
| 35 | + </nav> |
| 36 | + <button onClick={toggleTheme}>{theme}</button> |
| 37 | + </header> |
| 38 | + <main> |
| 39 | + <SiblingPageSidebar siblingPages={siblingPages} /> |
| 40 | + <Outlet /> {/* ์ฌ๊ธฐ์ ์ฃผ์ ์ฝํ
์ธ ๊ฐ ๋ค์ด๊ฐ๋๋ค */} |
| 41 | + <HeadingsSidebar headings={headings} /> |
| 42 | + </main> |
| 43 | + <footer> |
| 44 | + <ul> |
| 45 | + <li>GitHub</li> |
| 46 | + <li>Twitter</li> |
| 47 | + </ul> |
| 48 | + </footer> |
| 49 | + </div> |
| 50 | + ); |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +```ts title="shared/ui/layout/useThemeSwitcher.ts" |
| 55 | +export function useThemeSwitcher() { |
| 56 | + const [theme, setTheme] = useState("light"); |
| 57 | + |
| 58 | + function toggleTheme() { |
| 59 | + setTheme(theme === "light" ? "dark" : "light"); |
| 60 | + } |
| 61 | + |
| 62 | + useEffect(() => { |
| 63 | + document.body.classList.remove("light", "dark"); |
| 64 | + document.body.classList.add(theme); |
| 65 | + }, [theme]); |
| 66 | + |
| 67 | + return [theme, toggleTheme] as const; |
| 68 | +} |
| 69 | +``` |
| 70 | + |
| 71 | +์ฌ์ด๋๋ฐ์ ๊ตฌ์ฒด์ ์ธ ์ฝ๋๋ ์ฌ๋ฌ๋ถ ์์์ ๋งก๊ธฐ๊ฒ ์ต๋๋ค ๐. |
| 72 | + |
| 73 | +## layout์ widget ์ฌ์ฉํ๊ธฐ |
| 74 | + |
| 75 | +์ํฉ์ ๋ฐ๋ผ layout์ ํน์ ๋น์ฆ๋์ค ๋ก์ง์ ์ถ๊ฐํ๊ณ ์ถ์ ๋๊ฐ ์์ต๋๋ค. ํนํ [React Router][ext-react-router]์ ๊ฐ์ ๋ผ์ฐํฐ๋ฅผ ์ฌ์ฉํด ๊น์ด ์ค์ฒฉ๋ ๊ฒฝ๋ก๋ฅผ ๋ค๋ฃฐ ๋ ์ด๋ฌํ ์๊ตฌ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ layout์ shared๋ widgets ํด๋์ ๋๋ ๊ฒ์ด ์ด๋ ค์ธ ์ ์์ต๋๋ค. ์ด๋ [layer์ ๋ํ import ๊ท์น][import-rule-on-layers] ๋๋ฌธ์
๋๋ค: |
| 76 | + |
| 77 | +> slice์ module์ ์์ ๋ณด๋ค ํ์ layers์ ์์นํ ๋ค๋ฅธ slice๋ง importํ ์ ์์ต๋๋ค. |
| 78 | +
|
| 79 | +์ด ๋ฌธ์ ๊ฐ ์ ๋ง ์ค์ํ์ง ๋จผ์ ๊ณ ๋ คํด ๋ด์ผ ํฉ๋๋ค. ๋ ์ด์์์ด _์ ๋ง๋ก ํ์ํ๊ฐ์?_ ๊ทธ๋ฆฌ๊ณ ๊ทธ ๋ ์ด์์์ด _์ ๋ง๋ก widget์ด์ด์ผ ํ ๊น์?_ ๋ง์ฝ ํด๋น ๋น์ฆ๋์ค ๋ก์ง์ด 2-3๊ฐ์ ํ์ด์ง์์๋ง ์ฌ์ฉ๋๊ณ , ๋ ์ด์์์ด ๊ทธ widget์ ๊ฐ์ธ๋ ์ญํ ์ด๋ผ๋ฉด, ๋ค์ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ ๊ณ ๋ คํด ๋ณด์ธ์: |
| 80 | + |
| 81 | +1. **App ๋ ์ด์ด์์ ์ธ๋ผ์ธ์ผ๋ก ๋ ์ด์์ ์์ฑํ๊ธฐ** |
| 82 | + App ๋ ์ด์ด์์ ์ง์ ๋ ์ด์์์ ์ ์ํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ค์ฒฉ๋ ๋ผ์ฐํฐ๋ฅผ ์ฌ์ฉํ ๋ ํน์ ๊ฒฝ๋ก ๊ทธ๋ฃน์๋ง ํด๋น ๋ ์ด์์์ ์ ์ฉํ ์ ์์ด ์ ์ฐํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค. |
| 83 | + |
| 84 | +2. **๋ณต์ฌํ์ฌ ๋ถ์ฌ๋ฃ๊ธฐ** |
| 85 | + ์ฝ๋ ์ถ์ํ๋ ํญ์ ์ข์ ์ ํ์ ์๋๋๋ค. ํนํ ๋ ์ด์์์ ์์ฃผ ๋ณ๊ฒฝ๋์ง ์๊ธฐ ๋๋ฌธ์, ํ์ํ ๊ฒฝ์ฐ ํด๋น ํ์ด์ง๋ง ์์ ํ๋ ๊ฒ์ด ๋ ํจ์จ์ ์ผ ์ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ค๋ฅธ ํ์ด์ง์ ์ํฅ์ ์ฃผ์ง ์๊ณ ์์ ํ ์ ์์ต๋๋ค. ํ์๋ค์ด ๋ค๋ฅธ ํ์ด์ง๋ฅผ ์์ ํ๋ ๊ฑธ ์์๊น ๋ด ๊ฑฑ์ ๋๋ค๋ฉด, ํ์ด์ง ๊ฐ์ ๊ด๊ณ๋ฅผ ์ฃผ์์ผ๋ก ๋จ๊ฒจ๋ณด์ธ์. ํฐ ํ๋ก์ ํธ์์๋ ํ์
์ด ๋ ํธํด์ง ๊ฑฐ์์. |
| 86 | + |
| 87 | +์์ ๋ด์ฉ์ด ์ ์ ํ์ง ์์ ๊ฒฝ์ฐ, ๋ ์ด์์์ widget์ ํฌํจํ๋ ๋ ๊ฐ์ง ํด๊ฒฐ์ฑ
์ด ์์ต๋๋ค: |
| 88 | + |
| 89 | +1. **render props๋ slots ์ฌ์ฉํ๊ธฐ** |
| 90 | + ๋๋ถ๋ถ์ ํ๋ ์์ํฌ์์๋ ์ปดํฌ๋ํธ ๋ด๋ถ์ ํ์๋ UI ์์๋ฅผ ์ธ๋ถ์์ ์ ๋ฌํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. React์์๋ [render props][ext-render-props]๋ผ๊ณ ํ๋ฉฐ, Vue์์๋ [slots][ext-vue-slots]์ด๋ผ๊ณ ๋ถ๋ฆ
๋๋ค. |
| 91 | +2. **๋ ์ด์์์ App ๋ ์ด์ด๋ก ์ด๋ํ๊ธฐ** |
| 92 | + ๋ ์ด์์์ `app/layouts` ๋ฑ App ๋ ์ด์ด์ ์ ์ฅํ๊ณ ์ํ๋ widget์ ๊ตฌ์ฑํ ์๋ ์์ต๋๋ค. |
| 93 | + |
| 94 | +## ์ถ๊ฐ ์๋ฃ |
| 95 | + |
| 96 | +React ๋ฐ Remix(React Router์ ์ ์ฌ)์ ์ธ์ฆ ๋ ์ด์์ ๊ตฌ์ถ์ ๋ํ ์์๋ [ํํ ๋ฆฌ์ผ][tutorial]์์ ํ์ธํ์ค ์ ์์ต๋๋ค. |
| 97 | + |
| 98 | + |
| 99 | +[tutorial]: /docs/get-started/tutorial |
| 100 | +[import-rule-on-layers]: /docs/reference/layers#import-rule-on-layers |
| 101 | +[ext-react-router]: https://reactrouter.com/ |
| 102 | +[ext-render-props]: https://www.patterns.dev/react/render-props-pattern/ |
| 103 | +[ext-vue-slots]: https://vuejs.org/guide/components/slots |
| 104 | + |
0 commit comments