네브/로고 탭하면 각각 해당 데이터 출력 합니다.
export default function App() {
const mode = "WELCOME";
const topics = [
{ id: 1, title: "html", body: "html is ..." },
{ id: 2, title: "css", body: "css is ..." },
{ id: 3, title: "javascript", body: "javascript is ..." },
];
let content = null;
if (mode === "WELCOME") {
content = <Article title="Welcome" body="Hello, Web"></Article>;
} else if (mode === "READ") {
content = <Article title="Welcome" body="Hello, Read"></Article>;
}
return (
<div className="App">
<Header
title="WEB"
onChangeMode={() => {
mode = "WELCOME";
}}
></Header>
<Nav
topics={topics}
onChangeMode={(id) => {
mode = "READ";
}}
></Nav>
{content}
</div>
);
}
Completion
const mode = 'WELCOME';
펑션앱 바로 아래
상태 변수 초기값을 지정합니다.
let content = null;
펑션앱 토픽스 변수 아래
데이터 초기값을 지정 합니다.
if(mode === 'WELCOME') {
content = <Article title="Welcome" body="Hello, Web"></Article>
} else if(mode === 'READ') {
content = <Article title="Welcome" body="Hello, Read"></Article>
}
펑션앱 콘텐트 변수 아래
상태에 따라 출력할 테이터를 조건문으로 작성합니다.
{content}
펑션앱 리턴 네브태그 아래
<Article title="Welcome" body="Hello, Web"></Article>
이 코드는 위 엘스문에서 처리할거니까 삭제 합니다.
삭제한 자리에 유저가 선택한 상태에 해당하는 콘텐트 데이터를 바인딩 합니다.
<Header title="WEB" onChangeMode={()=>{
mode = 'WELCOME';
}}></Header>
<Nav topics={topics} onChangeMode={(id)=>{
mode = 'READ';
}}></Nav>
펑션앱 리턴 헤더/네브/
알러트는 이제 필요 없습니다.
유저가 탭 하면 상태를 변경합니다.
test
네브와 로고를 탭합니다.
에러가 나거나 아무일도 일어나지 않습니다.
앱 펑션이 다시 실행되지 않으면 리턴값은 변경되지 않습니다.
리액트 펑션은 데이터가 갱신되어야 다시 실행됩니다.
리액트는 지금 데이터가 갱신된것을 모르고 있습니다.
스테이트를 사용하면 데이터를 갱신했다고 펑션에 알려줄 수 있습니다.
에러 개선 합니다.
import "./styles.css";
import { useState } from "react";
Completion
import {useState} from 'react';
상단 임포트 아래
스테이트를 사용하기 위해 임포트합니다.
export default function App() {
const [mode, setMode] = useState("WELCOME");
const topics = [
{ id: 1, title: "html", body: "html is ..." },
{ id: 2, title: "css", body: "css is ..." },
{ id: 3, title: "javascript", body: "javascript is ..." },
];
let content = null;
if (mode === "WELCOME") {
content = <Article title="Welcome" body="Hello, Web"></Article>;
} else if (mode === "READ") {
content = <Article title="Welcome" body="Hello, Read"></Article>;
}
return (
<div className="App">
<Header
title="WEB"
onChangeMode={() => {
setMode("WELCOME");
}}
></Header>
<Nav
topics={topics}
onChangeMode={(id) => {
setMode("READ");
}}
></Nav>
{content}
</div>
);
}
Completion
const [mode, setMode] = useState('WELCOME');
펑션앱 바로 아래 모드 변수
모드를 스테이트로 변경합니다.
<Header title="WEB" onChangeMode={()=>{
setMode('WELCOME');
}}></Header>
<Nav topics={topics} onChangeMode={(id)=>{
setMode('READ');
}}></Nav>
펑션앱 리턴 헤더/네브/
스테이트 적용합니다.
test

네브/로고 탭합니다.
Hello, Web
Hello, Read
잘 출력되는지 체크합니다.
네브탭에 따라 다른 데이터가 출력되는 편이 좋겠습니다.
개선 합니다.
네브 탭했을 때 각각 다른 데이터 출력하도록 업그레이드 합니다.
export default function App() {
const [mode, setMode] = useState("WELCOME");
const [id, setId] = useState(null);
const topics = [
{ id: 1, title: "html", body: "html is ..." },
{ id: 2, title: "css", body: "css is ..." },
{ id: 3, title: "javascript", body: "javascript is ..." },
];
let content = null;
if (mode === "WELCOME") {
content = <Article title="Welcome" body="Hello, Web"></Article>;
} else if (mode === "READ") {
let title,
body = null;
for (let i = 0; i < topics.length; i++) {
if (topics[i].id === id) {
title = topics[i].title;
body = topics[i].body;
}
}
content = <Article title={title} body={body}></Article>;
}
return (
<div className="App">
<Header
title="WEB"
onChangeMode={() => {
setMode("WELCOME");
}}
></Header>
<Nav
topics={topics}
onChangeMode={(_id) => {
setMode("READ");
setId(_id);
}}
></Nav>
{content}
</div>
);
}
Completion
const [id, setId] = useState(null);
펑션앱 모드 변수 아래
유저가 네브에서 무엇을 선택했는지 알기 위해 아이디를 스테이트로 초기화 합니다.
<Nav topics={topics} onChangeMode={(_id)=>{
setMode('READ');
setId(_id);
}}></Nav>
펑션앱 리턴 네브태그
셋아이디 파라미터를 변경합니다.
리액트가 태그 내부 id를 스테이트의 0번 인덱스 id로 오해할 수 있습니다.
오해를 막기 위해 _id로 변경합니다.
setId가 다시 id로 변경되는 것을 막아야 하기 때문입니다.
let title, body = null;
펑션앱 모드리드 콘텐트변수 위
토픽스 타이틀/바디 데이터를 초기화 합니다.
for(let i=0; i<topics.length; i++) {
if(topics[i].id === id) {
title = topics[i].title;
body = topics[i].body;
}
}
펑션앱 모드리드 콘텐트변수 위
포문으로 토픽스 어레이를 텁니다.
이프문으로 현재 아이디와 어레이 아이디가 일치하는지 검증합니다.
일치할 경우 해당 어레이 인덱스를 저장합니다.
content = <Article title={title} body={body}></Article>
펑션앱 모드리드 콘텐트변수
아티클 데이터 바인딩 합니다.
test

네브를 탭해도 하단 데이터가 변경되지 않습니다.
문제를 찾아내서 개선합니다.
문제를 찾아서 개선합니다.
function Nav(props) {
const lis = [];
for (let i = 0; i < props.topics.length; i++) {
let t = props.topics[i];
lis.push(
<li key={t.id}>
<a
id={t.id}
href={"/read/" + t.id}
onClick={(event) => {
event.preventDefault();
props.onChangeMode(Number(event.target.id));
}}
>
{t.title}
</a>
</li>
);
}
return (
<nav>
<ol>{lis}</ol>
</nav>
);
}
Completion
<a id={t.id} href={'/read/'+t.id} onClick={event=>{
event.preventDefault();
props.onChangeMode(Number(event.target.id));
}}>{t.title}</a>
펑션네브 에이태그
에이 태그 체크합니다.
넘버 타입 아이디가 에이 태그로 들어가면 스트링으로 변합니다.
아이디는 넘버타입이어야 펑션이 제대로 작동할 것입니다.
즉, 현재 아이디가 스트링 타입이기 때문에 에러가 난것 입니다.
넘버 펑션으로 스트링을 넘버로 바꿉니다.
test

네브/로고 각각 탭합니다.
데이터가 잘 출력되는지 체크합니다.
Completion
import "./styles.css";
import { useState } from "react";
function Header(props) {
console.log("props", props.title);
return (
<header>
<h1>
<a
href="/"
onClick={(event) => {
event.preventDefault();
props.onChangeMode();
}}
>
{props.title}
</a>
</h1>
</header>
);
}
function Nav(props) {
const lis = [];
for (let i = 0; i < props.topics.length; i++) {
let t = props.topics[i];
lis.push(
<li key={t.id}>
<a
id={t.id}
href={"/read/" + t.id}
onClick={(event) => {
event.preventDefault();
props.onChangeMode(Number(event.target.id));
}}
>
{t.title}
</a>
</li>
);
}
return (
<nav>
<ol>{lis}</ol>
</nav>
);
}
function Article(props) {
return (
<article>
<h2>{props.title}</h2>
{props.body}
</article>
);
}
export default function App() {
const [mode, setMode] = useState("WELCOME");
const [id, setId] = useState(null);
const topics = [
{ id: 1, title: "html", body: "html is ..." },
{ id: 2, title: "css", body: "css is ..." },
{ id: 3, title: "javascript", body: "javascript is ..." },
];
let content = null;
if (mode === "WELCOME") {
content = <Article title="Welcome" body="Hello, Web"></Article>;
} else if (mode === "READ") {
let title,
body = null;
for (let i = 0; i < topics.length; i++) {
if (topics[i].id === id) {
title = topics[i].title;
body = topics[i].body;
}
}
content = <Article title={title} body={body}></Article>;
}
return (
<div className="App">
<Header
title="WEB"
onChangeMode={() => {
setMode("WELCOME");
}}
></Header>
<Nav
topics={topics}
onChangeMode={(_id) => {
setMode("READ");
setId(_id);
}}
></Nav>
{content}
</div>
);
}
Comment ver
// styles.css 파일을 가져와 애플리케이션의 스타일을 적용합니다.
import "./styles.css";
// React의 useState 훅을 가져와 함수형 컴포넌트에서 상태를 관리할 수 있도록 합니다.
import { useState } from "react";
/**
* Header 컴포넌트: 애플리케이션의 상단 영역을 담당합니다.
* @param {object} props - 컴포넌트에 전달되는 속성 객체입니다.
* @param {string} props.title - 헤더에 표시될 제목입니다.
* @param {function} props.onChangeMode - 제목 클릭 시 호출될 콜백 함수입니다.
*/
function Header(props) {
// props.title 값을 콘솔에 출력하여 디버깅 용도로 사용합니다.
console.log("props", props.title);
return (
<header>
<h1>
{/* 헤더 제목 링크: 클릭 시 기본 동작을 막고 onChangeMode 함수를 호출하여 페이지 모드를 변경합니다. */}
<a
href="/"
onClick={(event) => {
event.preventDefault(); // 기본 링크 동작(페이지 새로고침)을 방지합니다.
props.onChangeMode(); // 부모 컴포넌트로부터 전달받은 모드 변경 함수를 호출합니다.
}}
>
{props.title} {/* props로 전달받은 제목을 표시합니다. */}
</a>
</h1>
</header>
);
}
/**
* Nav 컴포넌트: 내비게이션 메뉴를 렌더링합니다.
* @param {object} props - 컴포넌트에 전달되는 속성 객체입니다.
* @param {Array<object>} props.topics - 내비게이션 항목으로 사용될 주제(topic) 배열입니다. 각 객체는 id, title, body를 포함합니다.
* @param {function} props.onChangeMode - 내비게이션 항목 클릭 시 호출될 콜백 함수입니다. 선택된 항목의 id를 인자로 전달합니다.
*/
function Nav(props) {
const lis = []; // 내비게이션 리스트 아이템(<li>)을 저장할 배열입니다.
// props로 전달받은 topics 배열을 순회하며 리스트 아이템을 생성합니다.
for (let i = 0; i < props.topics.length; i++) {
let t = props.topics[i]; // 현재 topic 객체를 가져옵니다.
lis.push(
// 각 topic에 대한 리스트 아이템을 생성합니다.
<li key={t.id}>
{/* 내비게이션 링크: 클릭 시 기본 동작을 막고 onChangeMode 함수를 호출합니다. */}
<a
id={t.id} // 링크의 id를 topic의 id로 설정하여 클릭 이벤트에서 접근할 수 있도록 합니다.
href={"/read/" + t.id} // 링크의 URL을 설정합니다.
onClick={(event) => {
event.preventDefault(); // 기본 링크 동작(페이지 이동)을 방지합니다.
// 부모 컴포넌트로부터 전달받은 모드 변경 함수를 호출하며, 클릭된 항목의 id를 숫자로 변환하여 전달합니다.
props.onChangeMode(Number(event.target.id));
}}
>
{t.title} {/* topic의 제목을 링크 텍스트로 표시합니다. */}
</a>
</li>
);
}
return (
<nav>
<ol>{lis}</ol> {/* 생성된 리스트 아이템들을 정렬된 리스트(<ol>)로 렌더링합니다. */}
</nav>
);
}
/**
* Article 컴포넌트: 메인 콘텐츠 영역을 담당합니다.
* @param {object} props - 컴포넌트에 전달되는 속성 객체입니다.
* @param {string} props.title - 아티클의 제목입니다.
* @param {string} props.body - 아티클의 본문 내용입니다.
*/
function Article(props) {
return (
<article>
<h2>{props.title}</h2> {/* props로 전달받은 제목을 표시합니다. */}
{props.body} {/* props로 전달받은 본문 내용을 표시합니다. */}
</article>
);
}
/**
* App 컴포넌트: 애플리케이션의 메인 엔트리 포인트입니다.
* 전체 UI를 구성하고 상태를 관리합니다.
*/
export default function App() {
// 현재 애플리케이션의 모드를 관리하는 상태 변수입니다 (예: "WELCOME", "READ", "CREATE" 등).
const [mode, setMode] = useState("WELCOME");
// 현재 선택된 topic의 ID를 관리하는 상태 변수입니다.
const [id, setId] = useState(null);
// 내비게이션 및 콘텐츠를 구성하는 데 사용될 주제(topic) 데이터 배열입니다.
const topics = [
{ id: 1, title: "html", body: "html is ..." },
{ id: 2, title: "css", body: "css is ..." },
{ id: 3, title: "javascript", body: "javascript is ..." },
];
let content = null; // 조건에 따라 렌더링될 콘텐츠 컴포넌트를 저장할 변수입니다.
// 현재 mode 상태에 따라 다른 콘텐츠를 렌더링합니다.
if (mode === "WELCOME") {
// mode가 "WELCOME"일 경우, 환영 메시지를 담은 Article 컴포넌트를 렌더링합니다.
content = <Article title="Welcome" body="Hello, Web"></Article>;
} else if (mode === "READ") {
// mode가 "READ"일 경우, 선택된 topic의 내용을 담은 Article 컴포넌트를 렌더링합니다.
let title,
body = null;
// topics 배열을 순회하여 현재 선택된 id와 일치하는 topic을 찾습니다.
for (let i = 0; i < topics.length; i++) {
if (topics[i].id === id) {
title = topics[i].title; // 해당 topic의 제목을 가져옵니다.
body = topics[i].body; // 해당 topic의 본문 내용을 가져옵니다.
}
}
content = <Article title={title} body={body}></Article>; // 찾은 topic 내용으로 Article 컴포넌트를 렌더링합니다.
}
return (
<div className="App">
{/* Header 컴포넌트를 렌더링하고, 제목은 "WEB"으로 설정합니다. */}
{/* onChangeMode 프롭스에 콜백 함수를 전달하여 클릭 시 mode를 "WELCOME"으로 변경하도록 합니다. */}
<Header
title="WEB"
onChangeMode={() => {
setMode("WELCOME");
}}
></Header>
{/* Nav 컴포넌트를 렌더링하고, topics 데이터를 전달합니다. */}
{/* onChangeMode 프롭스에 콜백 함수를 전달하여 클릭 시 mode를 "READ"로, id를 선택된 topic의 ID로 변경하도록 합니다. */}
<Nav
topics={topics}
onChangeMode={(_id) => {
setMode("READ");
setId(_id);
}}
></Nav>
{/* 현재 mode에 따라 동적으로 결정된 content 컴포넌트를 렌더링합니다. */}
{content}
</div>
);
}

'생활코딩! React 리액트 프로그래밍' 카테고리의 다른 글
| egoing - React - update (0) | 2025.06.24 |
|---|---|
| egoing - React - create (0) | 2025.06.23 |
| egoing - React - event (0) | 2025.06.21 |
| egoing - React - props - array (0) | 2025.06.21 |
| egoing - React - props (0) | 2025.06.21 |