๐ [Recat] React ํต์ฌ - ์ปดํฌ๋ํธ, JSX, ์์ฑ, ์ํ ๋ฑ - 2
![๐ [Recat] React ํต์ฌ - ์ปดํฌ๋ํธ, JSX, ์์ฑ, ์ํ ๋ฑ - 2](/assets/img/thumbnail/react-thumbnail.jpg)
[Recat] React ํต์ฌ - ์ปดํฌ๋ํธ, JSX, ์์ฑ, ์ํ ๋ฑ - 2
ํ์ผ์ ์ปดํฌ๋ํธ ์ ์ฅ ๋ฐ ์ข์ ํ๋ก์ ํธ ๊ตฌ์กฐ ํ์ฉ
1. ์ปดํฌ๋ํธ ํ์ผ ๋ถ๋ฆฌ
๊ธฐ์กด์ App.jsx
์ ์์ฑํ๋ ์ปดํฌ๋ํธ๋ค์ ๋ถ๋ฆฌ๋ ํ์ผ๋ก ๊ด๋ฆฌํ์ฌ ์ฝ๋์ ๊ตฌ์กฐํ ๋ฐ ์ ์ง๋ณด์์ฑ์ ํฅ์์ํค๊ธฐ ์ํจ
Header.jsx
์CoreConcept.jsx
๋ฅผcomponents
ํด๋๋ก ์ด๋ ๋ฐ ์ ์ฅ- ๊ฐ ์ปดํฌ๋ํธ๋ ํด๋น ํ์ผ์์
export default
๋ฌธ๋ฒ์ผ๋ก ๋ด๋ณด๋- ์:
export default function Header() {...}
- ์:
2. App.jsx์์ ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ
App.jsx
์์Header
,CoreConcept
๋ฅผimport
import { CORE_CONCEPTS } from "./data.js";
import Header from "./components/Header.jsx";
import CoreConcept from "./components/CoreConcept.jsx";
์ปดํฌ๋ํธ ์์ ์ปดํฌ๋ํธ ์คํ์ผ ํ์ผ ์ ์ฅํ๊ธฐ
- ๊ด๋ จ ํ์ผ(
Header.jsx
,Header.css
)์ ๊ฐ์ ํด๋์ ๋ฌถ์ด ๊ด๋ฆฌ - ์ปดํฌ๋ํธ๋ณ ์ ๋ฆฌ๋ก ์ ์ง๋ณด์์ฑ๊ณผ ๊ตฌ์กฐ ์ดํด๋ ํฅ์
import './Header.css';
โ ์ ์ฉ ๋ฐฉ์ ์ฃผ์์ฌํญ
- CSS๋ ์ ์ญ ๋ฒ์๋ก ์ ์ฉ๋๋ฉฐ, ๋จ์ํ
Header.css
๋ฅผHeader.jsx
์์ importํ๋ค๊ณ ํด์ ํด๋น ์คํ์ผ์ด ๊ทธ ์ปดํฌ๋ํธ์๋ง ์๋ ํ์ ๋์ง๋ ์์. - ์:
<h1>
์คํ์ผ์ด ์ ์๋์ด ์๋ค๋ฉด, ๋ชจ๋<h1>
์์์ ์ ์ฉ๋จ. - ์คํ์ผ์ ์ปดํฌ๋ํธ๋ณ๋ก ๋ถ๋ฆฌํ๋ฉด ๊ด๋ฆฌ๊ฐ ์ฌ์์ง๊ณ ๋ช ํํ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ถ ์ ์์
- ๋ค๋ง CSS๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ์ญ ์ ์ฉ๋๋ฏ๋ก, ์ดํ ๊ฐ์์์ ์๊ฐ๋ CSS ๋ชจ๋ ๋๋ CSS-in-JS์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์คํ์ผ ๋ฒ์ ์ ํ์ ์ ์ฉํ ์ ์์
์ปดํฌ๋ํธ ๊ตฌ์ฑ : children prop ์์ฑ
๋ฆฌ์กํธ์์๋ <TabButton>Components</TabButton>
์ ๊ฐ์ด ์ปดํฌ๋ํธ ํ๊ทธ ์ฌ์ด์ ๋ด์ฉ์ ์์ฑํ๋ฉด, ๊ทธ ๋ด์ฉ์ children
prop์ผ๋ก ์ ๋ฌ๋จ
export default function TabButton({ children } ๋๋ props) {
return <li><button>{children}๋๋{props.children}</button></li>;
}
children vs label ๋ฐฉ์ ๋น๊ต
- ๋ ๋ฐฉ์ ๋ชจ๋ ๋ฒํผ ํ ์คํธ๋ฅผ ์ ๋ฌํ ์ ์์
๋ฐฉ์ 1: children ๋ฐฉ์
<TabButton>Components</TabButton>
๋ฐฉ์ 2: ๋ช ์์ props ๋ฐฉ์
<TabButton label="Components" />
// ์ปดํฌ๋ํธ ๋ด๋ถ์์: <button>{props.label}</button>
์ด๋ฒคํธ ์ฒ๋ฆฌํ๊ธฐ
- ์ด๋ฒคํธ ํธ๋ค๋ฌ ํจ์๋ ๊ฐ์ ์ ๋ฌํด์ผ ํ๋ฏ๋ก
ํจ์ ์ด๋ฆ๋ง
๋๊น onClick={handleClick}
โonClick={handleClick()}
โ โ ํจ์๊ฐ ์ฆ์ ์คํ๋จ
/* ์ปดํฌ๋ํธ ์ฌ์ด์ text๋ props.children๋ฐ์์์๋ค. */
export default function TabButton({ children }) {
function handleClick() {
console.log("hellow world");
}
//({children})๊ฐ๋ฅ ์ปดํฌ๋ํธ ์์ฑ์ธ label๋ก ๋๊ธฐ๋ฉด ({label}) ๊ฐ๋ฅ
return (
<li>
{/* props์ ๋ด์ฅ๊ฐ์ฒด์ธ children ์ปดํฌ๋ํธ ํ๊ทธ ์ฌ์ด์ text๋ฅผ ๋ฐ์์ด */}
{/* ์ด๋ฒคํธ ์ฒ๋ฆฌ onClick ๋ฒํผ ํด๋ฆญ์ ์ด๋ฒคํธ ๋ฐ์ handleClick ํจ์ ํธ์ถ */}
<button onClick={handleClick}>{children}</button>
</li>
);
}
ํจ์๋ฅผ Prop(์์ฑ)์ ๊ฐ์ผ๋ก ์ ๋ฌํ๊ธฐ
App ์ปดํฌ๋ํธ์์ onSelect
prop์ผ๋ก ํจ์๋ฅผ TabButton์ ์ ๋ฌ
// App.jsx
function handleSelect() {
console.log("Selected!");
}
<TabButton onSelect={handleSelect}>Components</TabButton>
TabButton ์ปดํฌ๋ํธ์์๋ onSelect
๋ฅผ ๋ฐ์ ๋ด๋ถ <button>
์ onClick
์ ์ฐ๊ฒฐ
export default function TabButton({ children, onSelect }) {
return <li><button onClick={onSelect}>{children}</button></li>;
}
์ด๋ฒคํธ ํจ์์ ์ปค์คํ ์ธ์ ์ ๋ฌํ๊ธฐ
ํ์ดํ ํจ์ ์ฌ์ฉ
onSelect={handleSelect}
๋ก ๋๊ธฐ๋ฉด ๋ฆฌ์กํธ๊ฐ ์ด๋ค ๊ฐ์ ์ ๋ฌํด์ผ ํ ์ง ๋ชจ๋ฆ onClick
์ด๋ฒคํธ์ ์ธ์๊ฐ์ ์ ๋ฌํ๊ธฐ ์ํด์๋ ํ์ดํ ํจ์๋ฅผ ์ฌ์ฉํด์ผํจ
<TabButton onSelect={() => handleSelect('Components')}>Components</TabButton>
<TabButton onSelect={() => handleSelect('JSX')}>JSX</TabButton>
- ํ์ดํ ํจ์๋ ์ง๊ธ ์คํ๋์ง ์์ผ๋ฉฐ, ๋ฒํผ ํด๋ฆญ ์์๋ง ์คํ๋จ
- ๋ฐ๋ผ์ ๋ด๋ถ์์
handleSelect()
๋ฅผ ํธ์ถํ๋ฉฐ ์ํ๋ ์ธ์ ์ ๋ฌ์ด ๊ฐ๋ฅ
State(์ํ) ๊ด๋ฆฌ & Hooks(ํ ) ์ฌ์ฉ๋ฒ
useState๋?
- ๋ฆฌ์กํธ๊ฐ ์ ๊ณตํ๋ Hook ํจ์
- ์ปดํฌ๋ํธ์ ์ํ(๋ฐ์ดํฐ) ๋ฅผ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๋ฉฐ,
- ์ํ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์ปดํฌ๋ํธ๊ฐ ์๋์ผ๋ก ๋ค์ ์คํ(๋ ๋๋ง) ๋จ
import { useState } from 'react';
const [selectedTopic, setSelectedTopic] = useState('Please click a button');
selectedTopic
: ํ์ฌ ์ํ ๊ฐ (์ด๊ธฐ๊ฐ์ผ๋ก ์ค์ ๋จ) setSelectedTopic
: ์ํ๋ฅผ ์
๋ฐ์ดํธํ๋ ํจ์. ํธ์ถ ์ ์ปดํฌ๋ํธ๊ฐ ์ฌ์คํ๋จ
setSelectedTopic()
์ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ๋ณ๊ฒฝ
function handleSelect(selectedButton) {
setSelectedTopic(selectedButton);
console.log(selectedTopic) //์ด์ ๊ฐ์ด ์ถ๋ ฅ
}
setSelectedTopic()
์ ํธ์ถํ๋ฉด ์ปดํฌ๋ํธ ํจ์ ์ ์ฒด๊ฐ ๋ค์ ์คํ๋จ- ๊ทธ๋ฌ๋ ์ํ ์ ๋ฐ์ดํธ๋ ์ฆ์ ๋ฐ์๋์ง ์๊ณ ๋น๋๊ธฐ์ ์ผ๋ก ์์ฝ๋จ
- ๊ทธ ๊ฒฐ๊ณผ,
setSelectedTopic()
๋ฐ๋ก ๋ค์์console.log(selectedTopic)
์ ์ฐ์ผ๋ฉด ์ด์ ๊ฐ์ด ์ถ๋ ฅ๋จ - ์กฐ๊ฑด๋ฌธ, ๋ฐ๋ณต๋ฌธ, ๋ด๋ถ ํจ์ ๋ฑ์์๋ ํธ์ถ ๋ถ๊ฐ
- ์ํ ๋ณ๊ฒฝ ํจ์๋ ํญ์ ๋น๋๊ธฐ์ ์ผ๋ก ์๋ํ๋ฉฐ, ์ปดํฌ๋ํธ๋ฅผ ์ฌ์คํ์ํด
- ์ํ ๊ฐ์ ๋ณ๊ฒฝ ๋ถ๊ฐ ์์๋ก ์ ์ง (
const
) useState
๋ ๋ฆฌ์กํธ์์ UI๋ฅผ ์ํ ๊ธฐ๋ฐ์ผ๋ก ๋์ ์ผ๋ก ๋ง๋ค๊ธฐ ์ํ ํต์ฌ ๋๊ตฌ- ์ด๋ฒคํธ + ์ํ + ์ฌ๋ ๋๋ง์ด๋ผ๋ ํ๋ฆ์ ํตํด ๋์
๋ฐ์ดํฐ ๊ธฐ๋ฐ State(์ํ) ๊ฐ์ ธ์ค๊ธฐ ๋ฐ ์ถ๋ ฅ
์ํ ์ด๊ธฐํ
์ํ ์ด๊ธฐ๊ฐ์ components
๋ก ์ค์
const [selectedTopic, setSelectedTopic] = useState("components");
handleSelect
ํจ์ ๋ด์์ ์ํ ์
๋ฐ์ดํธ
function handleSelect(selectedButton) {
setSelectedTopic(selectedButton);
}
data.js
์์ EXAMPLES
๊ฐ์ฒด๋ฅผ import
import { EXAMPLES } from "./data.js";
JSX์์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋์ ์ผ๋ก ์ ๊ทผ selectedTopic ๊ฐ์ด ๋ณํจ์ ๋ฐ๋ผ EXAMPLES ๊ฐ์ฒด๊ฐ์ด ๋์ ์ผ๋ก ์ถ๋ ฅ
<h3>{EXAMPLES[selectedTopic].title}</h3>
<p>{EXAMPLES[selectedTopic].description}</p>
<pre>
<code>{EXAMPLES[selectedTopic].code}</code>
</pre>
์ด๊ธฐ ์ํ ์์ธ ์ฒ๋ฆฌ
- ์ํ ์ด๊ธฐ๊ฐ์ด
components
๋ก ์ค์ ๋์ด ์๊ธฐ ๋๋ฌธ์ ์ฒซ ํ๋ฉด ๋ ๋๋ง ์ ์ค๋ฅ ์์ - ์ด๊ธฐ ์ํ๋ก
"Please click a button"
๊ณผ ๊ฐ์ ์กด์ฌํ์ง ์๋ ํค๋ฅผ ๋ฃ์ผ๋ฉดEXAMPLES[selectedTopic]
๊ฐundefined
๊ฐ ๋์ด ์ค๋ฅ ๋ฐ์
์กฐ๊ฑด์ ์ฝํ ์ธ ๋ ๋๋ง
๊ธฐ์กด์๋ useState
์ด๊ธฐ๊ฐ์ components
๋ก ์ค์ ๋์ด ์์ด์ components
๊ด๋ จ contents๊ฐ ์ถ๋ ฅ ๋์์ง๋ง ์ด๊ธฐํ๋ฉด์ โPlease select a topicโ ํ
์คํธ ์ถ๋ ฅํ๊ณ ์ถ๋ค๋ฉด
์ํ ์ด๊ธฐ๊ฐ์ ๋น ๋ฌธ์์ด๋ก ์ค์
const [selectedTopic, setSelectedTopic] = useState('');
- ์๋ฌด ๋ฒํผ๋ ์ ํ๋์ง ์์์์ ๋ํ๋ด๊ธฐ ์ํด ๋น ๋ฌธ์์ด(โโ) ์ฌ์ฉ
EXAMPLES['']
๋ ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์, ์กฐ๊ฑด ์์ด ์ ๊ทผํ๋ฉด ์ค๋ฅ ๋ฐ์
์กฐ๊ฑด๋ถ ๋ ๋๋ง ๋ฐฉ์ 3๊ฐ์ง
์ผํญ ์ฐ์ฐ์ ์ฌ์ฉ
{!selectedTopic
? <p>Please select a topic</p>
: <div id="tab-content">
<h3>{EXAMPLES[selectedTopic].title}</h3>
<p>{EXAMPLES[selectedTopic].description}</p>
<pre><code>{EXAMPLES[selectedTopic].code}</code></pre>
AND ์ฐ์ฐ์ (&&
) ์ฌ์ฉ
{!selectedTopic && <p>Please select a topic</p>}
{selectedTopic && (
<div id="tab-content">
<h3>{EXAMPLES[selectedTopic].title}</h3>
<p>{EXAMPLES[selectedTopic].description}</p>
<pre><code>{EXAMPLES[selectedTopic].code}</code></pre>
</div>
)}
๋ณ์์ JSX ์ ์ฅ (if๋ฌธ ํ์ฉ)
let tabContent = <p>Please select a topic</p>;
if (selectedTopic) {
tabContent = (
<div id="tab-content">
<h3>{EXAMPLES[selectedTopic].title}</h3>
<p>{EXAMPLES[selectedTopic].description}</p>
<pre><code>{EXAMPLES[selectedTopic].code}</code></pre>
</div>
);
}
// JSX ๋ด์ ๋ณ์ ์ฝ์
{tabContent}
CSS ์คํ์ผ๋ง ๋ฐ ๋์ ์คํ์ผ๋ง
- ์ฌ์ฉ์๊ฐ ํด๋ฆญํ ๋ฒํผ(TabButton)์ ์๊ฐ์ ์ผ๋ก ๊ฐ์กฐ(ํ์ฑํ ์คํ์ผ ์ ์ฉ)
- ์ ํ๋ ๋ฒํผ์๋ง
active
ํด๋์ค๋ฅผ ๋์ ์ผ๋ก ์ถ๊ฐ
className์ JSX์์ ์คํ์ผ๋ง์ ์ํ ์์ฑ
- HTML์
class
์ ๊ฐ์ง๋ง, JSX์์๋className
์ ์ฌ์ฉ isSelected
๊ฐtrue
์ด๋ฉดactive
ํด๋์ค ์ ์ฉfalse
์ด๋ฉด ํด๋์ค ์์
/* ์ปดํฌ๋ํธ ์ฌ์ด์ text๋ props.children๋ฐ์์์๋ค. */
export default function TabButton({ children, onSelect, isSelected }) {
//({children})๊ฐ๋ฅ ์ปดํฌ๋ํธ ์์ฑ์ธ label๋ก ๋๊ธฐ๋ฉด ({label}) ๊ฐ๋ฅ
return (
<li>
{/* props์ ๋ด์ฅ๊ฐ์ฒด์ธ children ์ปดํฌ๋ํธ ํ๊ทธ ์ฌ์ด์ text๋ฅผ ๋ฐ์์ด */}
{/* ์ด๋ฒคํธ ์ฒ๋ฆฌ onClick ๋ฒํผ ํด๋ฆญ์ ์ด๋ฒคํธ ๋ฐ์ handleClick ํจ์ ํธ์ถ */}
<button className={isSelected ? "active" : undefined} onClick={onSelect}>
{children}
</button>
</li>
);
}
App ์ปดํฌ๋ํธ์์ ์ํ์ ๋ฐ๋ผ isSelected
์ ๋ฌ
<TabButton
isSelected={selectedTopic === "components"}
onSelect={() => handleSelect("components")}
>
Components
</TabButton>
<TabButton
isSelected={selectedTopic === "jsx"}
onSelect={() => handleSelect("jsx")}
>
JSX
</TabButton>
<TabButton
isSelected={selectedTopic === "props"}
onSelect={() => handleSelect("props")}
>
Props
</TabButton>
<TabButton
isSelected={selectedTopic === "state"}
onSelect={() => handleSelect("state")}
>
State
</TabButton>
selectedTopic
์ํ์ ํ์ฌ ๋ฒํผ์ ์๋ณ์('components'
,'jsx'
,'props'
,'state'
)๋ฅผ ๋น๊ตํดtrue/false
๊ฒฐ์ - ์ด ๊ฐ์ด
TabButton
์isSelected
๋ก ์ ๋ฌ๋จ
List(๋ฆฌ์คํธ) ๋ฐ์ดํฐ ๋์ ์ถ๋ ฅ
๊ธฐ์กด์๋ CoreConcept
์ปดํฌ๋ํธ๋ฅผ ์๋์ผ๋ก 4๋ฒ ์ถ๋ ฅ๋๊ฒํจ ๋ฐ์ดํฐ(CORE_CONCEPTS
)๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์๋์ผ๋ก ์ฝ๋๋ ์์ ํด์ผ ํจ ์ด๋ ๊ฒ ํ๋ฉด ์ค๋ณต ์ฝ๋๊ฐ ๋ง๊ณ , ์ ์ง๋ณด์์ฑ์ด ๋ฎ์
<CoreConcept {...CORE_CONCEPTS[0]} />
<CoreConcept {...CORE_CONCEPTS[1]} />
<CoreConcept {...CORE_CONCEPTS[2]} />
<CoreConcept {...CORE_CONCEPTS[3]} />
.map()์ ํ์ฉํ ๋์ ๋ ๋๋ง
map()
์์์ JSX ์์๋ฅผ ๋ฐํ CORE_CONCEPTS
๋ฐฐ์ด์ ํฌ๊ธฐ์ ๋ง๊ฒ ์๋์ผ๋ก ๋ ๋๋ง๋จ ํญ๋ชฉ์ด ์ถ๊ฐ/์ ๊ฑฐ๋๋ฉด ์ฝ๋ ์์ ์์ด ์๋ ๋ฐ์
{CORE_CONCEPTS.map((item) => (
<CoreConcept key={item.title} {...item} />
))}
- ๋ฆฌ์กํธ๊ฐ ํญ๋ชฉ์ ๊ณ ์ ํ๊ฒ ์๋ณํ ์ ์์ด์ผ ํจ
- ํจ์จ์ ์ธ ๋ฆฌ๋ ๋๋ง ๋ฐ DOM ์ ๋ฐ์ดํธ๋ฅผ ์ํด ์ฌ์ฉ๋จ
- ๋ฐ๋ณต ์ปดํฌ๋ํธ์๋ ๋ฐ๋์ ๊ณ ์ ํ
key
๊ฐ์ด ํ์ - ์์:
title
,id
, ํน์ ๊ณ ์ ํ ์๋ณ์ ์ฌ์ฉ
๐ Reference
- ใํ๊ธ์๋งใ React ์๋ฒฝ ๊ฐ์ด๋ 2025 with React Router & Redux | Udemy
- ์ด๋ฏธ์ง ์ถ์ Freepik | ์ฌ์ธ์ AI ํฌ๋ฆฌ์์ดํฐ๋ธ ํด