이번 시간에 우리는 state를 배우게 되었다. 우선 state가 필요한 이유를 설명하기 위해 아래 코드를 먼저 살펴보자
function App() {
const mode = 'WELCOME'//event가 발생 했을 때 변경되는 변수 값
const topics = [
{ id: 1, title: 'html', body: 'html is..' },
{ id: 2, title: 'css', body: 'css is..' },
{ id: 3, title: 'javascript', body: 'javascript is..' }
]
return (
<div>
<Header title="WEB" onChangeMode={() => {
mode = 'WELCOME';
}}></Header>
<Nav topics={topics} onChangeMode={(_id) => {
mode = 'READ';
}}></Nav>
</div >
);
}
export default App; //contact App_7.js
해당 코드의 컴포넌트들을 각기 연관지어서 설명을 하자면 Header컴포넌트가 눌렸을 때 mode는 WELCOME이 되어야 하고 Nav 컴포넌트가 눌리면 mode는 READ가 되는 것이다. 하지만 실제로 동작은 그렇지 못하다. 짐작으론 현재 우리가 보고 있는 스크립트는 App_7 또는 index.js와 import 되어 있다. 이는 곧 의존관계인 것이고 해당 코드가 한번 파싱이 된다는 것이다. 즉, 지속적으로 파싱 또는 랜더링이 되지 않는 것이다. 그래서 js에서도 지속적으로 상태를 확인하고 변동해야하 할 때 setTimeout을 사용하는 경우가 있다. 그래서 React에서는 이를 해결하기 위해 useState라는 모듈을 사용한다. 이를 변경한 코드를 보기 전에 useState를 잠깐 보면 아래와 같다.
const _mode = useState('WELCOME')
const mode = _mode[0];
const setMode = mode[1];
useState는 인자를 두가지를 가진다. 첫 번째 인자로는 기본값 상태이고 두 번째는 상태를 변경할 수 있는 함수이다. 위와같이 표기하는 방법도 있지만 이를 한번에 처리 할 수 있는 방법이 있다. 바로 배열 비구조화 할당을 사용하는 것이다. 코드는 아래와 같다.
const [mode, setMode] = useState('WELCOME');
이와 같이 작성하고 이를 이용해서 상태를 변경할 것이다. 이제 App 컴포넌트를 변경하면 아래와 같다.
...
return (
<div>
<Header title="WEB" onChangeMode={() => {
setMode('WELCOME')
}}></Header>
<Nav topics={topics} onChangeMode={(_id) => {
setMode('READ')
}}></Nav>
</div >
);
...
이렇게 작성하면 이제 브라우저에서도 잘 작되는 모습을 볼 수 있다. 이를 응용해서 코드를 마저 작성하면 아래와 같다.
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>
<Header title="WEB" onChangeMode={() => {
setMode('WELCOME')
}}></Header>
<Nav topics={topics} onChangeMode={(_id) => {
setMode('READ')
setId(_id);
}}></Nav>
{content}
</div >
);
}
export default App;
기존에 있는 Article 컴포넌트를 핸들링 할 수 있게 content변수에 담을 수 있게 했고 이를 Header컴포넌트와 Nav컴포넌트를 통해서 상태가 변경 되면 if문을 통해서 조건문이 실행 되고 두 번째 useState인 id를 setid(_id)인 props로 인가 받아 Article의 태그 속성들이 변경되는 논리로 이루어져 있다. 어떻게보면 단순하지만 하나하나 따져보면 굉장히 복잡하게 이루어져 있다. 잘만 정리한다면 어려움이 없을 것이다. 아래는 전체코드이다.
import { useState } from "react";
function Header(props) {
return <header>
<title>section04</title>
<h1><a href="/" onClick={(event) => {
event.preventDefault();
props.onChangeMode();
}}>{props.title}</a></h1>
</header>
}
function Article(props) {
return <article>
<h2>{props.title}</h2>
{props.body}
</article>
}
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)); //함수를 props로 호출해서 컨트롤 하는 것이다.
//props.onChangeMode(t.id);
}}
>{t.title}</a></li>
)
}
return <nav>
<ol>
{lis}
</ol>
</nav>
}
function App() {
//첫번째 인자는 상태이고 두번째 인자는 상태를 변경하는 함수이다. WELCOME은 초기 값이다.
// let _mode = useState('WELCOME') //event가 발생 했을 때 변경되는 변수 값
// const mode = _mode[0];
// const setMode = mode[1];
const [mode, setMode] = useState('WELCOME'); //setMode로 변경된 값이 mode로 값이 전달
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>
<Header title="WEB" onChangeMode={() => {
// mode = 'WELCOME';
setMode('WELCOME')
}}></Header>
<Nav topics={topics} onChangeMode={(_id) => {
setMode('READ')
setId(_id);
}}></Nav>
{content}
</div >
);
}
export default App; //contact App_7.js