<Activity>
<Activity>๋ฅผ ์ฌ์ฉํ๋ฉด ์์ ์ปดํฌ๋ํธ์ UI์ ๋ด๋ถ ์ํ๋ฅผ ์จ๊ธฐ๊ณ ๋ณต์ํ ์ ์์ต๋๋ค.
<Activity mode={visibility}>
<Sidebar />
</Activity>๋ ํผ๋ฐ์ค
<Activity>
Activity๋ฅผ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ผ๋ถ๋ฅผ ์จ๊ธธ ์ ์์ต๋๋ค.
<Activity mode={isShowingSidebar ? "visible" : "hidden"}>
<Sidebar />
</Activity>Activity ๊ฒฝ๊ณ๊ฐ ์จ๊ฒจ์ง๋ฉด, React๋ display: "none" CSS ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํด ์์ ์ปดํฌ๋ํธ๋ฅผ ์๊ฐ์ ์ผ๋ก ์จ๊น๋๋ค. ๋ํ Effect๋ฅผ ํด๋ฆฐ์
ํ๊ณ ํ์ฑ ๊ตฌ๋
์ ๋ชจ๋ ํด์ ํฉ๋๋ค.
์จ๊ฒจ์ง ์ํ์์๋ ์์ ์ปดํฌ๋ํธ๋ ์๋ก์ด props์ ๋ฐ์ํ์ฌ ๋ฆฌ๋ ๋๋ง๋์ง๋ง, ๋๋จธ์ง ์ฝํ ์ธ ๋ณด๋ค ๋ฎ์ ์ฐ์ ์์๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
๊ฒฝ๊ณ๊ฐ ๋ค์ ๋ณด์ด๊ฒ ๋๋ฉด, React๋ ์ด์ ์ํ๋ฅผ ๋ณต์ํ ์ํ๋ก ์์ ์ปดํฌ๋ํธ๋ฅผ ํ์ํ๊ณ Effect๋ฅผ ๋ค์ ์์ฑํฉ๋๋ค.
์ด๋ฌํ ๋ฐฉ์์ผ๋ก Activity๋ โ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ โ์ ๋ ๋๋งํ๋ ๋ฉ์ปค๋์ฆ์ผ๋ก ์๊ฐํ ์ ์์ต๋๋ค. ๋ค์ ํ์๋ ๊ฐ๋ฅ์ฑ์ด ์๋ ์ฝํ ์ธ ๋ฅผ ์์ ํ ์ญ์ ํ๋ ๋์ , Activity๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ์ฝํ ์ธ ์ UI์ ๋ด๋ถ ์ํ๋ฅผ ์ ์งํ๊ณ ๋ณต์ํ ์ ์์ผ๋ฉฐ, ๋์์ ์จ๊ฒจ์ง ์ฝํ ์ธ ๊ฐ ์์น ์๋ ๋ถ์์ฉ์ ์ผ์ผํค์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
์๋์์ ๋ ๋ง์ ์์๋ฅผ ํ์ธํ์ธ์.
Props
children: ํ์ํ๊ฑฐ๋ ์จ๊ธธ UI์ ๋๋ค.mode:'visible'๋๋'hidden'์ค ํ๋์ ๋ฌธ์์ด ๊ฐ์ ๋๋ค. ์๋ตํ๋ฉด ๊ธฐ๋ณธ๊ฐ์'visible'์ ๋๋ค.
์ฃผ์ ์ฌํญ
- Activity๊ฐ ViewTransition ๋ด๋ถ์์ ๋ ๋๋ง๋๊ณ , startTransition์ผ๋ก ์ธํ ์
๋ฐ์ดํธ์ ๊ฒฐ๊ณผ๋ก ๋ณด์ด๊ฒ ๋๋ฉด ViewTransition์
enter์ ๋๋ฉ์ด์ ์ด ํ์ฑํ๋ฉ๋๋ค. ์จ๊ฒจ์ง๋ฉดexit์ ๋๋ฉ์ด์ ์ด ํ์ฑํ๋ฉ๋๋ค. - ํ
์คํธ๋ง ๋ ๋๋งํ๋ Activity๋ ์๋ฌด๊ฒ๋ ๋ ๋๋งํ์ง ์์ต๋๋ค. ๊ฐ์์ฑ ๋ณ๊ฒฝ์ ์ ์ฉํ ๋์ํ๋ DOM ์๋ฆฌ๋จผํธ๊ฐ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์๋ฅผ ๋ค์ด
const ComponentThatJustReturnsText = () => "Hello, World!"์ธ ๊ฒฝ์ฐ,<Activity mode="hidden"><ComponentThatJustReturnsText /></Activity>๋ DOM์ ์๋ฌด๋ฐ ์ถ๋ ฅ๋ ์์ฑํ์ง ์์ต๋๋ค.
์ฌ์ฉ๋ฒ
์จ๊ฒจ์ง ์ปดํฌ๋ํธ์ ์ํ ๋ณต์ํ๊ธฐ
React์์ ์ปดํฌ๋ํธ๋ฅผ ์กฐ๊ฑด๋ถ๋ก ํ์ํ๊ฑฐ๋ ์จ๊ธฐ๋ ค๋ฉด ์ผ๋ฐ์ ์ผ๋ก ํด๋น ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ง์ดํธํ๊ฑฐ๋ ๋ง์ดํธ ํด์ ํฉ๋๋ค.
{isShowingSidebar && (
<Sidebar />
)}ํ์ง๋ง ์ปดํฌ๋ํธ๋ฅผ ๋ง์ดํธ ํด์ ํ๋ฉด ๋ด๋ถ ์ํ๊ฐ ์ฌ๋ผ์ง๋๋ฐ, ์ด๊ฒ์ด ํญ์ ์ํ๋ ๋์์ ์๋๋๋ค.
Activity ๊ฒฝ๊ณ๋ฅผ ์ฌ์ฉํด ์ปดํฌ๋ํธ๋ฅผ ์จ๊ธฐ๋ฉด React๋ ๋์ค์ ์ํด ์ํ๋ฅผ โ์ ์ฅโํฉ๋๋ค.
<Activity mode={isShowingSidebar ? "visible" : "hidden"}>
<Sidebar />
</Activity>์ด๋ ๊ฒ ํ๋ฉด ์ปดํฌ๋ํธ๋ฅผ ์จ๊ธด ํ ๋์ค์ ์ด์ ์ํ ๊ทธ๋๋ก ๋ณต์ํ ์ ์์ต๋๋ค.
๋ค์ ์์์๋ ํผ์น ์ ์๋ ์น์ ์ด ์๋ ์ฌ์ด๋๋ฐ๊ฐ ์์ต๋๋ค. โOverviewโ๋ฅผ ๋๋ฅด๋ฉด ์๋์ ์ธ ๊ฐ์ ํ์ ํญ๋ชฉ์ด ํ์๋ฉ๋๋ค. ๋ฉ์ธ ์ฑ ์์ญ์๋ ์ฌ์ด๋๋ฐ๋ฅผ ์จ๊ธฐ๊ณ ํ์ํ๋ ๋ฒํผ๋ ์์ต๋๋ค.
Overview ์น์ ์ ํผ์น ๋ค์ ์ฌ์ด๋๋ฐ๋ฅผ ๋ซ์๋ค๊ฐ ๋ค์ ์ด์ด๋ณด์ธ์.
import { useState } from 'react'; import Sidebar from './Sidebar.js'; export default function App() { const [isShowingSidebar, setIsShowingSidebar] = useState(true); return ( <> {isShowingSidebar && ( <Sidebar /> )} <main> <button onClick={() => setIsShowingSidebar(!isShowingSidebar)}> Toggle sidebar </button> <h1>Main content</h1> </main> </> ); }
Overview ์น์
์ ํญ์ ์ ํ ์ํ๋ก ์์ํฉ๋๋ค. isShowingSidebar๊ฐ false๋ก ๋ฐ๋๋ฉด์ ์ฌ์ด๋๋ฐ๋ฅผ ๋ง์ดํธ ํด์ ํ๊ธฐ ๋๋ฌธ์ ๋ชจ๋ ๋ด๋ถ ์ํ๊ฐ ์์ค๋ฉ๋๋ค.
์ด๊ฒ์ด ๋ฐ๋ก Activity๋ฅผ ์ฌ์ฉํ๊ธฐ ์๋ฒฝํ ์ฌ๋ก์ ๋๋ค. ์๊ฐ์ ์ผ๋ก ์จ๊ธฐ๋ฉด์๋ ์ฌ์ด๋๋ฐ์ ๋ด๋ถ ์ํ๋ฅผ ๋ณด์กดํ ์ ์์ต๋๋ค.
์ฌ์ด๋๋ฐ์ ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ Activity ๊ฒฝ๊ณ๋ก ๊ต์ฒดํด๋ณด๊ฒ ์ต๋๋ค.
// Before
{isShowingSidebar && (
<Sidebar />
)}
// After
<Activity mode={isShowingSidebar ? 'visible' : 'hidden'}>
<Sidebar />
</Activity>์๋ก์ด ๋์์ ํ์ธํด๋ณด์ธ์.
import { Activity, useState } from 'react'; import Sidebar from './Sidebar.js'; export default function App() { const [isShowingSidebar, setIsShowingSidebar] = useState(true); return ( <> <Activity mode={isShowingSidebar ? 'visible' : 'hidden'}> <Sidebar /> </Activity> <main> <button onClick={() => setIsShowingSidebar(!isShowingSidebar)}> Toggle sidebar </button> <h1>Main content</h1> </main> </> ); }
์ด์ ์ฌ์ด๋๋ฐ์ ๋ด๋ถ ์ํ๊ฐ ๊ตฌํ์ ๋ณ๊ฒฝํ์ง ์๊ณ ๋ ๋ณต์๋ฉ๋๋ค.
์จ๊ฒจ์ง ์ปดํฌ๋ํธ์ DOM ๋ณต์ํ๊ธฐ
Activity ๊ฒฝ๊ณ๋ display: none์ ์ฌ์ฉํด ์์ ์ปดํฌ๋ํธ๋ฅผ ์จ๊ธฐ๊ธฐ ๋๋ฌธ์, ์จ๊ฒจ์ง ์ํ์์๋ ์์์ DOM์ด ๋ณด์กด๋ฉ๋๋ค. ์ด๋ ์ฌ์ฉ์๊ฐ ๋ค์ ์ํธ์์ฉํ ๊ฐ๋ฅ์ฑ์ด ์๋ UI ๋ถ๋ถ์ ์์ ์ํ๋ฅผ ์ ์งํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.
์ด ์์์์ Contact ํญ์๋ ์ฌ์ฉ์๊ฐ ๋ฉ์์ง๋ฅผ ์
๋ ฅํ ์ ์๋ <textarea>๊ฐ ์์ต๋๋ค. ํ
์คํธ๋ฅผ ์
๋ ฅํ ํ Home ํญ์ผ๋ก ๋ณ๊ฒฝํ๋ค๊ฐ ๋ค์ Contact ํญ์ผ๋ก ๋์์ค๋ฉด ์
๋ ฅํ ๋ฉ์์ง๊ฐ ์ฌ๋ผ์ง๋๋ค.
export default function Contact() { return ( <div> <p>Send me a message!</p> <textarea /> <p>You can find me online here:</p> <ul> <li>admin@mysite.com</li> <li>+123456789</li> </ul> </div> ); }
App์์ Contact๋ฅผ ์์ ํ ๋ง์ดํธ ํด์ ํ๊ธฐ ๋๋ฌธ์
๋๋ค. Contact ํญ์ด ๋ง์ดํธ ํด์ ๋๋ฉด <textarea> ์๋ฆฌ๋จผํธ์ ๋ด๋ถ DOM ์ํ๊ฐ ์์ค๋ฉ๋๋ค.
Activity ๊ฒฝ๊ณ๋ฅผ ์ฌ์ฉํด ํ์ฑ ํญ์ ํ์ํ๊ณ ์จ๊ธฐ๋๋ก ์ ํํ๋ฉด ๊ฐ ํญ์ DOM ์ํ๋ฅผ ๋ณด์กดํ ์ ์์ต๋๋ค. ํ ์คํธ๋ฅผ ์ ๋ ฅํ๊ณ ๋ค์ ํญ์ ์ ํํด๋ณด๋ฉด ์ ๋ ฅํ ๋ฉ์์ง๊ฐ ๋ ์ด์ ์ด๊ธฐํ๋์ง ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
import { Activity, useState } from 'react'; import TabButton from './TabButton.js'; import Home from './Home.js'; import Contact from './Contact.js'; export default function App() { const [activeTab, setActiveTab] = useState('contact'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'contact'} onClick={() => setActiveTab('contact')} > Contact </TabButton> <hr /> <Activity mode={activeTab === 'home' ? 'visible' : 'hidden'}> <Home /> </Activity> <Activity mode={activeTab === 'contact' ? 'visible' : 'hidden'}> <Contact /> </Activity> </> ); }
๋ค์ ํ๋ฒ, Activity ๊ฒฝ๊ณ๋ฅผ ํตํด Contact ํญ์ ๋ด๋ถ ์ํ๋ฅผ ๊ตฌํ ๋ณ๊ฒฝ ์์ด ๋ณด์กดํ ์ ์์์ต๋๋ค.
ํ์๋ ๊ฐ๋ฅ์ฑ์ด ์๋ ์ฝํ ์ธ ์ฌ์ ๋ ๋๋งํ๊ธฐ
์ง๊ธ๊น์ง Activity๋ฅผ ์ฌ์ฉํด ์ฌ์ฉ์๊ฐ ์ํธ์์ฉํ ์ฝํ ์ธ ๋ฅผ ์์ ์ํ๋ฅผ ์ญ์ ํ์ง ์๊ณ ์จ๊ธฐ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ดค์ต๋๋ค.
ํ์ง๋ง Activity ๊ฒฝ๊ณ๋ ์ฌ์ฉ์๊ฐ ์์ง ์ฒ์ ๋ณด์ง ๋ชปํ ์ฝํ ์ธ ๋ฅผ ์ค๋น ํ๋ ๋ฐ๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
<Activity mode="hidden">
<SlowComponent />
</Activity>Activity ๊ฒฝ๊ณ๊ฐ ์ด๊ธฐ ๋ ๋๋ง ์ค์ ์จ๊ฒจ์ง ์ํ๋ผ๋ฉด, ์์ ์ปดํฌ๋ํธ๋ ํ์ด์ง์ ๋ณด์ด์ง ์์ง๋ง ์ฌ์ ํ ๋ ๋๋ง ๋ฉ๋๋ค. ๋ค๋ง ๋ณด์ด๋ ์ฝํ ์ธ ๋ณด๋ค ๋ฎ์ ์ฐ์ ์์๋ก ๋ ๋๋ง๋๋ฉฐ, Effect๋ ๋ง์ดํธ๋์ง ์์ต๋๋ค.
์ด๋ฌํ ์ฌ์ ๋ ๋๋ง ์ ํตํด ์์ ์ปดํฌ๋ํธ๊ฐ ํ์ํ ์ฝ๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ๋ก๋ํ ์ ์์ผ๋ฏ๋ก, ๋์ค์ Activity ๊ฒฝ๊ณ๊ฐ ๋ณด์ด๊ฒ ๋ ๋ ๋ก๋ฉ ์๊ฐ์ด ์ค์ด๋ค์ด ๋ ๋น ๋ฅด๊ฒ ํ์ํ ์ ์์ต๋๋ค.
์์๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ด ๋ฐ๋ชจ์์ Posts ํญ์ ์ผ๋ถ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํฉ๋๋ค. ํญ์ ๋๋ฅด๋ฉด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋์ Suspense ํด๋ฐฑ์ด ํ์๋ฉ๋๋ค.
import { useState, Suspense } from 'react'; import TabButton from './TabButton.js'; import Home from './Home.js'; import Posts from './Posts.js'; export default function App() { const [activeTab, setActiveTab] = useState('home'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'posts'} onClick={() => setActiveTab('posts')} > Posts </TabButton> <hr /> <Suspense fallback={<h1>๐ Loading...</h1>}> {activeTab === 'home' && <Home />} {activeTab === 'posts' && <Posts />} </Suspense> </> ); }
App์ด ํญ์ด ํ์ฑํ๋ ๋๊น์ง Posts๋ฅผ ๋ง์ดํธํ์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค.
App์ ์์ ํ์ฌ Activity ๊ฒฝ๊ณ๋ก ํ์ฑ ํญ์ ํ์ํ๊ณ ์จ๊ธฐ๋๋ก ํ๋ฉด, ์ฑ์ด ์ฒ์ ๋ก๋๋ ๋ Posts๊ฐ ์ฌ์ ๋ ๋๋ง๋์ด ๋ณด์ด๊ธฐ ์ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
์ด์ Posts ํญ์ ํด๋ฆญํด๋ณด์ธ์.
import { Activity, useState, Suspense } from 'react'; import TabButton from './TabButton.js'; import Home from './Home.js'; import Posts from './Posts.js'; export default function App() { const [activeTab, setActiveTab] = useState('home'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'posts'} onClick={() => setActiveTab('posts')} > Posts </TabButton> <hr /> <Suspense fallback={<h1>๐ Loading...</h1>}> <Activity mode={activeTab === 'home' ? 'visible' : 'hidden'}> <Home /> </Activity> <Activity mode={activeTab === 'posts' ? 'visible' : 'hidden'}> <Posts /> </Activity> </Suspense> </> ); }
์จ๊ฒจ์ง Activity ๊ฒฝ๊ณ ๋๋ถ์ Posts๊ฐ ๋ ๋น ๋ฅธ ๋ ๋๋ง์ ์ค๋นํ ์ ์์์ต๋๋ค.
์จ๊ฒจ์ง Activity ๊ฒฝ๊ณ๋ก ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ ๋ ๋๋งํ๋ ๊ฒ์ ์ฌ์ฉ์๊ฐ ๋ค์์ ์ํธ์์ฉํ ๊ฐ๋ฅ์ฑ์ด ์๋ UI ๋ถ๋ถ์ ๋ก๋ฉ ์๊ฐ์ ์ค์ด๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ๋๋ค.
ํ์ด์ง ๋ก๋ ์ค ์ํธ์์ฉ ์๋ ๋์ด๊ธฐ
React์๋ ์ ํ์ ํ์ด๋๋ ์ด์ ์ด๋ผ๋ ๋ด๋ถ ์ฑ๋ฅ ์ต์ ํ๊ฐ ํฌํจ๋์ด ์์ต๋๋ค. ์ด๋ ์ฑ์ ์ด๊ธฐ HTML์ ์ฒญํฌ ๋จ์ ๋ก ํ์ด๋๋ ์ด์ ํ์ฌ, ํ์ด์ง์ ๋ค๋ฅธ ์ปดํฌ๋ํธ๊ฐ ์ฝ๋๋ ๋ฐ์ดํฐ๋ฅผ ์์ง ๋ก๋ํ์ง ์์๋๋ผ๋ ์ผ๋ถ ์ปดํฌ๋ํธ๋ฅผ ์ํธ์์ฉ ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค.
Suspense ๊ฒฝ๊ณ๋ ์์ฐ์ค๋ฝ๊ฒ ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ์๋ก ๋ ๋ฆฝ์ ์ธ ๋จ์๋ก ๋๋๊ธฐ ๋๋ฌธ์ ์ ํ์ ํ์ด๋๋ ์ด์ ์ ์ฐธ์ฌํฉ๋๋ค.
function Page() {
return (
<>
<MessageComposer />
<Suspense fallback="Loading chats...">
<Chats />
</Suspense>
</>
)
}์ฌ๊ธฐ์ MessageComposer๋ Chats๊ฐ ๋ง์ดํธ๋์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์์ํ๊ธฐ ์ ์๋ ํ์ด์ง์ ์ด๊ธฐ ๋ ๋๋ง ์ค์ ์์ ํ ํ์ด๋๋ ์ด์
๋ ์ ์์ต๋๋ค.
์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ๊ฐ๋ณ ๋จ์๋ก ๋๋๋ฉด React๊ฐ ์ฑ์ ์๋ฒ ๋ ๋๋ง๋ HTML์ ์ฒญํฌ ๋จ์๋ก ํ์ด๋๋ ์ด์ ํ ์ ์์ด, ์ฑ์ ์ผ๋ถ๊ฐ ๊ฐ๋ฅํ ํ ๋น ๋ฅด๊ฒ ์ํธ์์ฉ ๊ฐ๋ฅํด์ง๋๋ค.
๊ทธ๋ ๋ค๋ฉด Suspense๋ฅผ ์ฌ์ฉํ์ง ์๋ ํ์ด์ง๋ ์ด๋ป๊ฒ ๋ ๊น์?
๋ค์ ํญ ์์๋ฅผ ๋ณด๊ฒ ์ต๋๋ค.
function Page() {
const [activeTab, setActiveTab] = useState('home');
return (
<>
<TabButton onClick={() => setActiveTab('home')}>
Home
</TabButton>
<TabButton onClick={() => setActiveTab('video')}>
Video
</TabButton>
{activeTab === 'home' && (
<Home />
)}
{activeTab === 'video' && (
<Video />
)}
</>
)
}์ฌ๊ธฐ์ React๋ ์ ์ฒด ํ์ด์ง๋ฅผ ํ ๋ฒ์ ํ์ด๋๋ ์ด์
ํด์ผ ํฉ๋๋ค. Home์ด๋ Video๊ฐ ๋ ๋๋ง์ด ๋๋ฆฌ๋ค๋ฉด ํ์ด๋๋ ์ด์
์ค์ ํญ ๋ฒํผ์ด ๋ฐ์ํ์ง ์๋ ๊ฒ์ฒ๋ผ ๋๊ปด์ง ์ ์์ต๋๋ค.
ํ์ฑ ํญ ์ฃผ์์ Suspense๋ฅผ ์ถ๊ฐํ๋ฉด ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
function Page() {
const [activeTab, setActiveTab] = useState('home');
return (
<>
<TabButton onClick={() => setActiveTab('home')}>
Home
</TabButton>
<TabButton onClick={() => setActiveTab('video')}>
Video
</TabButton>
<Suspense fallback={<Placeholder />}>
{activeTab === 'home' && (
<Home />
)}
{activeTab === 'video' && (
<Video />
)}
</Suspense>
</>
)
}โฆํ์ง๋ง ์ด๋ ๊ฒ ํ๋ฉด ์ด๊ธฐ ๋ ๋๋ง์์ Placeholder ํด๋ฐฑ์ด ํ์๋๊ธฐ ๋๋ฌธ์ UI๊ฐ ๋ณ๊ฒฝ๋ฉ๋๋ค.
๋์ Activity๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. Activity ๊ฒฝ๊ณ๋ ์์์ ํ์ํ๊ณ ์จ๊ธฐ๊ธฐ ๋๋ฌธ์ ์ด๋ฏธ ์์ฐ์ค๋ฝ๊ฒ ์ปดํฌ๋ํธ ํธ๋ฆฌ๋ฅผ ๋ ๋ฆฝ์ ์ธ ๋จ์๋ก ๋๋๋๋ค. ๊ทธ๋ฆฌ๊ณ Suspense์ฒ๋ผ ์ด ๊ธฐ๋ฅ์ ํตํด ์ ํ์ ํ์ด๋๋ ์ด์ ์ ์ฐธ์ฌํ ์ ์์ต๋๋ค.
์์๋ฅผ ์์ ํ์ฌ ํ์ฑ ํญ ์ฃผ์์ Activity ๊ฒฝ๊ณ๋ฅผ ์ฌ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
function Page() {
const [activeTab, setActiveTab] = useState('home');
return (
<>
<TabButton onClick={() => setActiveTab('home')}>
Home
</TabButton>
<TabButton onClick={() => setActiveTab('video')}>
Video
</TabButton>
<Activity mode={activeTab === "home" ? "visible" : "hidden"}>
<Home />
</Activity>
<Activity mode={activeTab === "video" ? "visible" : "hidden"}>
<Video />
</Activity>
</>
)
}์ด์ ์ด๊ธฐ ์๋ฒ ๋ ๋๋ง๋ HTML์ ์๋ ๋ฒ์ ๊ณผ ๋์ผํ๊ฒ ๋ณด์ด์ง๋ง, Activity ๋๋ถ์ React๋ Home์ด๋ Video๋ฅผ ๋ง์ดํธํ๊ธฐ๋ ์ ์ ํญ ๋ฒํผ์ ๋จผ์ ํ์ด๋๋ ์ด์
ํ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ ์ฝํ ์ธ ๋ฅผ ์จ๊ธฐ๊ณ ํ์ํ๋ ๊ฒ ์ธ์๋, Activity ๊ฒฝ๊ณ๋ ํ์ด์ง์ ์ด๋ ๋ถ๋ถ์ด ๋ ๋ฆฝ์ ์ผ๋ก ์ํธ์์ฉ ๊ฐ๋ฅํด์ง ์ ์๋์ง React์ ์๋ ค์ค์ผ๋ก์จ ํ์ด๋๋ ์ด์ ์ค ์ฑ์ ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค.
ํ์ด์ง๊ฐ ์ฝํ ์ธ ์ ์ผ๋ถ๋ฅผ ์จ๊ธฐ์ง ์๋๋ผ๋, ํ์ด๋๋ ์ด์ ์ฑ๋ฅ์ ํฅ์์ํค๊ธฐ ์ํด ํญ์ ๋ณด์ด๋ Activity ๊ฒฝ๊ณ๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
function Page() {
return (
<>
<Post />
<Activity>
<Comments />
</Activity>
</>
);
}๋ฌธ์ ํด๊ฒฐ
์จ๊ฒจ์ง ์ปดํฌ๋ํธ์ ์์น ์๋ ๋ถ์์ฉ์ด ์์ต๋๋ค
Activity ๊ฒฝ๊ณ๋ ์์์ display: none์ ์ค์ ํ๊ณ Effect๋ฅผ ํด๋ฆฐ์
ํ์ฌ ์ฝํ
์ธ ๋ฅผ ์จ๊น๋๋ค. ๋ฐ๋ผ์ ๋ถ์์ฉ์ ์ ์ ํ ํด๋ฆฐ์
ํ๋ ๋๋ถ๋ถ์ ์ ์์ฑ๋ React ์ปดํฌ๋ํธ๋ ์ด๋ฏธ Activity์ ์ํด ์จ๊ฒจ์ง๋ ๊ฒ์ ๋ํด ๊ฒฌ๊ณ ํฉ๋๋ค.
ํ์ง๋ง ์จ๊ฒจ์ง ์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ ํด์ ๋ ์ปดํฌ๋ํธ์ ๋ค๋ฅด๊ฒ ๋์ํ๋ ๋ช ๊ฐ์ง ์ํฉ์ด ์์ต๋๋ค. ํนํ ์จ๊ฒจ์ง ์ปดํฌ๋ํธ์ DOM์ ์ ๊ฑฐ๋์ง ์๊ธฐ ๋๋ฌธ์, ํด๋น DOM์ ๋ถ์์ฉ์ ์ปดํฌ๋ํธ๊ฐ ์จ๊ฒจ์ง ํ์๋ ์ง์๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด <video> ํ๊ทธ๋ฅผ ์๊ฐํด๋ณด์ธ์. ์ผ๋ฐ์ ์ผ๋ก ํด๋ฆฐ์
์ด ํ์ํ์ง ์์ต๋๋ค. ๋น๋์ค๋ฅผ ์ฌ์ ์ค์ด๋๋ผ๋ ํ๊ทธ๋ฅผ ๋ง์ดํธ ํด์ ํ๋ฉด ๋ธ๋ผ์ฐ์ ์์ ๋น๋์ค์ ์ค๋์ค ์ฌ์์ด ์ค์ง๋๊ธฐ ๋๋ฌธ์
๋๋ค. ๋น๋์ค๋ฅผ ์ฌ์ํ ํ ์ด ๋ฐ๋ชจ์์ Home์ ๋๋ฌ๋ณด์ธ์.
import { useState } from 'react'; import TabButton from './TabButton.js'; import Home from './Home.js'; import Video from './Video.js'; export default function App() { const [activeTab, setActiveTab] = useState('video'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'video'} onClick={() => setActiveTab('video')} > Video </TabButton> <hr /> {activeTab === 'home' && <Home />} {activeTab === 'video' && <Video />} </> ); }
๋น๋์ค๊ฐ ์์๋๋ก ์ฌ์์ ๋ฉ์ถฅ๋๋ค.
์ด์ ์ฌ์ฉ์๊ฐ ๋ง์ง๋ง์ผ๋ก ์์ฒญํ ํ์์ฝ๋๋ฅผ ๋ณด์กดํ์ฌ ๋น๋์ค ํญ์ผ๋ก ๋์์์ ๋ ์ฒ์๋ถํฐ ๋ค์ ์์ํ์ง ์๋๋ก ํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด๋ด ์๋ค.
์ด๊ฒ์ Activity๋ฅผ ์ฌ์ฉํ๊ธฐ ์๋ฒฝํ ์ฌ๋ก์ ๋๋ค!
App์ ์์ ํ์ฌ ๋นํ์ฑ ํญ์ ๋ง์ดํธ ํด์ ํ๋ ๋์ ์จ๊ฒจ์ง Activity ๊ฒฝ๊ณ๋ก ์จ๊ธฐ๊ณ , ์ด๋ฒ์๋ ๋ฐ๋ชจ๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง ํ์ธํด๋ณด์ธ์.
import { Activity, useState } from 'react'; import TabButton from './TabButton.js'; import Home from './Home.js'; import Video from './Video.js'; export default function App() { const [activeTab, setActiveTab] = useState('video'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'video'} onClick={() => setActiveTab('video')} > Video </TabButton> <hr /> <Activity mode={activeTab === 'home' ? 'visible' : 'hidden'}> <Home /> </Activity> <Activity mode={activeTab === 'video' ? 'visible' : 'hidden'}> <Video /> </Activity> </> ); }
์ด๋ฐ! ๋น๋์ค๊ฐ ์จ๊ฒจ์ง ํ์๋ ๋น๋์ค์ ์ค๋์ค๊ฐ ๊ณ์ ์ฌ์๋ฉ๋๋ค. ํญ์ <video> ์๋ฆฌ๋จผํธ๊ฐ ์ฌ์ ํ DOM์ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋น๋์ค๋ฅผ ์ผ์์ ์งํ๋ ํด๋ฆฐ์ ํจ์๊ฐ ์๋ Effect๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
export default function VideoTab() {
const ref = useRef();
useLayoutEffect(() => {
const videoRef = ref.current;
return () => {
videoRef.pause()
}
}, []);
return (
<video
ref={ref}
controls
playsInline
src="..."
/>
);
}๊ฐ๋
์ ์ผ๋ก ํด๋ฆฐ์
์ฝ๋๊ฐ ์ปดํฌ๋ํธ์ UI๊ฐ ์๊ฐ์ ์ผ๋ก ์จ๊ฒจ์ง๋ ๊ฒ๊ณผ ์ฐ๊ฒฐ๋์ด ์๊ธฐ ๋๋ฌธ์ useEffect ๋์ useLayoutEffect๋ฅผ ํธ์ถํฉ๋๋ค. ์ผ๋ฐ effect๋ฅผ ์ฌ์ฉํ๋ฉด (์๋ฅผ ๋ค์ด) ๋ค์ suspend๋๋ Suspense ๊ฒฝ๊ณ๋ View Transition์ ์ํด ์ฝ๋๊ฐ ์ง์ฐ๋ ์ ์์ต๋๋ค.
์๋ก์ด ๋์์ ํ์ธํด๋ณด์ธ์. ๋น๋์ค๋ฅผ ์ฌ์ํ๊ณ Home ํญ์ผ๋ก ์ ํํ ๋ค์ ๋ค์ Video ํญ์ผ๋ก ๋์์๋ณด์ธ์.
import { Activity, useState } from 'react'; import TabButton from './TabButton.js'; import Home from './Home.js'; import Video from './Video.js'; export default function App() { const [activeTab, setActiveTab] = useState('video'); return ( <> <TabButton isActive={activeTab === 'home'} onClick={() => setActiveTab('home')} > Home </TabButton> <TabButton isActive={activeTab === 'video'} onClick={() => setActiveTab('video')} > Video </TabButton> <hr /> <Activity mode={activeTab === 'home' ? 'visible' : 'hidden'}> <Home /> </Activity> <Activity mode={activeTab === 'video' ? 'visible' : 'hidden'}> <Video /> </Activity> </> ); }
์๋ฒฝํ๊ฒ ์๋ํฉ๋๋ค! ํด๋ฆฐ์
ํจ์๋ Activity ๊ฒฝ๊ณ์ ์ํด ์จ๊ฒจ์ง ๋๋ง๋ค ๋น๋์ค ์ฌ์์ด ์ค์ง๋๋๋ก ๋ณด์ฅํ๋ฉฐ, ๋ ์ข์ ์ ์ <video> ํ๊ทธ๊ฐ ์ ๊ฑฐ๋์ง ์๊ธฐ ๋๋ฌธ์ ํ์์ฝ๋๊ฐ ๋ณด์กด๋๊ณ , ์ฌ์ฉ์๊ฐ ์์ฒญ์ ๊ณ์ํ๊ธฐ ์ํด ๋ค์ ์ ํํ ๋ ๋น๋์ค๋ฅผ ์ด๊ธฐํํ๊ฑฐ๋ ๋ค์ ๋ค์ด๋ก๋ํ ํ์๊ฐ ์๋ค๋ ๊ฒ์
๋๋ค.
์ด๋ Activity๋ฅผ ์ฌ์ฉํ์ฌ ์จ๊ฒจ์ง์ง๋ง ์ฌ์ฉ์๊ฐ ๊ณง ๋ค์ ์ํธ์์ฉํ ๊ฐ๋ฅ์ฑ์ด ์๋ UI ๋ถ๋ถ์ ์์ DOM ์ํ๋ฅผ ๋ณด์กดํ๋ ์ข์ ์์์ ๋๋ค.
์์์์ ๋ณด๋ฏ์ด <video>์ ๊ฐ์ ํน์ ํ๊ทธ์ ๊ฒฝ์ฐ ๋ง์ดํธ ํด์ ์ ์จ๊ธฐ๊ธฐ๊ฐ ๋ค๋ฅธ ๋์์ ๋ณด์
๋๋ค. ์ปดํฌ๋ํธ๊ฐ ๋ถ์์ฉ์ด ์๋ DOM์ ๋ ๋๋งํ๊ณ , Activity ๊ฒฝ๊ณ๊ฐ ์ด๋ฅผ ์จ๊ธธ ๋ ํด๋น ๋ถ์์ฉ์ ๋ฐฉ์งํ๊ณ ์ถ๋ค๋ฉด ํด๋ฆฐ์
์ ์ํ return ํจ์๊ฐ ์๋ Effect๋ฅผ ์ถ๊ฐํ์ธ์.
๊ฐ์ฅ ํํ ๊ฒฝ์ฐ๋ ๋ค์ ํ๊ทธ์ผ ๊ฒ์ ๋๋ค.
<video><audio><iframe>
ํ์ง๋ง ์ผ๋ฐ์ ์ผ๋ก ๋๋ถ๋ถ์ React ์ปดํฌ๋ํธ๋ ์ด๋ฏธ Activity ๊ฒฝ๊ณ์ ์ํด ์จ๊ฒจ์ง๋ ๊ฒ์ ๋ํด ๊ฒฌ๊ณ ํด์ผ ํฉ๋๋ค. ๊ฐ๋ ์ ์ผ๋ก โ์จ๊ฒจ์งโ Activity๋ ๋ง์ดํธ ํด์ ๋ ๊ฒ์ผ๋ก ์๊ฐํด์ผ ํฉ๋๋ค.
์ ์ ํ ํด๋ฆฐ์
์ด ์๋ ๋ค๋ฅธ Effect๋ฅผ ๋ฏธ๋ฆฌ ๋ฐ๊ฒฌํ๋ ค๋ฉด <StrictMode> ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค. ์ด๋ Activity ๊ฒฝ๊ณ๋ฟ๋ง ์๋๋ผ React์ ๋ค๋ฅธ ๋ง์ ๋์์๋ ์ค์ํฉ๋๋ค.
์จ๊ฒจ์ง ์ปดํฌ๋ํธ์ Effect๊ฐ ์คํ๋์ง ์์ต๋๋ค
<Activity>๊ฐ โhiddenโ ์ํ์ผ ๋ ๋ชจ๋ ์์์ Effect๊ฐ ํด๋ฆฐ์
๋ฉ๋๋ค. ๊ฐ๋
์ ์ผ๋ก ์์์ ๋ง์ดํธ ํด์ ๋์ง๋ง, React๋ ๋์ค์ ์ํด ์ํ๋ฅผ ์ ์ฅํฉ๋๋ค. ์ด๋ Activity์ ๊ธฐ๋ฅ์
๋๋ค. ์จ๊ฒจ์ง UI ๋ถ๋ถ์ ๋ํ ๊ตฌ๋
์ด ํ์ฑํ๋์ง ์์ ์จ๊ฒจ์ง ์ฝํ
์ธ ์ ํ์ํ ์์
๋์ด ์ค์ด๋ค๊ธฐ ๋๋ฌธ์
๋๋ค.
์ปดํฌ๋ํธ์ ๋ถ์์ฉ์ ํด๋ฆฐ์ ํ๊ธฐ ์ํด Effect๊ฐ ๋ง์ดํธ๋๋ ๊ฒ์ ์์กดํ๊ณ ์๋ค๋ฉด, ๋์ ๋ฐํ๋ ํด๋ฆฐ์ ํจ์์์ ์์ ์ ์ํํ๋๋ก Effect๋ฅผ ๋ฆฌํฉํฐ๋งํ์ธ์.
๋ฌธ์ ๊ฐ ์๋ Effect๋ฅผ ๋ฏธ๋ฆฌ ์ฐพ์ผ๋ ค๋ฉด <StrictMode> ์ถ๊ฐ๋ฅผ ๊ถ์ฅํฉ๋๋ค. ์ด๋ ์์์น ๋ชปํ ๋ถ์์ฉ์ ํฌ์ฐฉํ๊ธฐ ์ํด Activity ๋ง์ดํธ ํด์ ์ ๋ง์ดํธ๋ฅผ ๋ฏธ๋ฆฌ ์ํํฉ๋๋ค.