인터넷 쇼핑몰에서 옷을 주문할 때, 원하는 옷을 장바구니에 담고 결제를 하려고 보니 다른 옷이 더 마음에 들어서 처음 담은 옷을 빼고 새로운 옷을 담으면 내가 결제해야 할 금액도 즉각적으로 변경된다. 이는 장바구니의 상태가 변한다고 말할 수 있다!
React에서 데이터를 다루는 두 가지 방법에는 State와 Props가 있다.
State :
Props :
props 사용 방법
1. 하위 컴포넌트에 전달하고자 하는 값(data)과 속성을 정의한다.
2. props를 이용하여 정의된 값과 속성을 전달한다. (속성명은 임의로 지정 가능, 여러 개 지정도 가능)
3. 전달받은 props를 렌더링한다.
// 컴포넌트 선언
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
{/* JSX 속성 및 값 할당 방법 : <Child attribute={value} >*/}
<Child text={"I'm the eldest child"} />
</div>
);
};
// props 전달 및 렌더링
function Child(props) {
return (
<div className="child">
<p>{props.text}</p>
</div>
);
};
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child>I'm the eldest child</Child>
</div>
);
};
function Child(props) {
return (
<div className="child">
<p>{props.children}</p>
</div>
);
};
import "./styles.css";
const App = () => {
const itemOne = "React를";
const itemTwo = "배우고 있습니다.";
return (
<div className="App">
{/* Learn 컴포넌트에 itemOne 과 itemTwo 를
props 로 전달하세요 */}
<Learn one={itemOne} two={itemTwo}/>
</div>
);
};
const Learn = (props) => {
// 전달받은 props 를 아래 <div> tag 사이에 사용하여
// "React를 배우고 있습니다" 라는 문장이 렌더링되도록 컴포넌트를 완성하세요
return <div className="Learn">{props.one} {props.two}</div>;
};
export default App;
Hook : 함수형 컴포넌트에서 사용되는 state와 관련된 기술들을 모아서 일컫는 말. 대표적으로 useState()
와 useEffect()
가 있다.
state 구별법 :
useState
// useState 불러오기
import { useState } from "react";
function CheckboxExample() {
// const [state 저장 변수, state 갱신 함수] = useState(상태 초기 값);
const [isChecked, setIsChecked] = useState(false); // useState 호출 후 리턴 값을 구조 분해 할당한 변수
const handleChecked = (event) => {
setIsChecked(event.target.checked);
};
return (
<div className="App">
<input type="checkbox" checked={isChecked} onChange={handleChecked} />
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
</div>
);
}
// checkbox Ex
import React, { useState } from "react";
import "./styles.css";
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
/* 구조 분해 할당 코드를 풀어 쓴 것
const stateHookArray = useState(false);
const isChecked = stateHookArray[0];
const setIsChecked = stateHookArray[1];
*/
const handleChecked = (event) => {
setIsChecked(event.target.checked);
};
return (
<div className="App">
<input type="checkbox" checked={isChecked} onChange={handleChecked} />
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
</div>
);
}
export default CheckboxExample;
DOM의 처리 방식과 유사하나 문법적으로 차이가 있다.
// html 이벤트 처리 방식
<button onclick="handleEvent()">Event</button>
// React 이벤트 처리 방식
<button onClick={handleEvent}>Event</button>
<input>
, <textarea>
, <select>
와 같은 폼(Form) 엘리먼트의 입력값이 변경될 때 마다 발생하는 이벤트이다. React에서는 이러한 변경될 수 있는 입력값을 일반적으로 컴포넌트의 state로 관리하고 업데이트한다.function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value); // 이벤트 객체에 담겨있는 input값을 읽어와서 setState를 통해 새로운 state로 갱신
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<h1>{name}</h1>
</div>
)
};
<a>
를 통한 링크 이동 등과 같이 주로 사용자의 행동에 따라 애플리케이션이 반응해야 할 때 자주 사용하는 이벤트이다.function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<button onClick={alert(name)}>Button</button>
<h1>{name}</h1>
</div>
);
};
위와 같이 onClick 이벤트에 alert(name) 함수를 바로 호출하면 컴포넌트가 렌더링 될 때 함수 자체가 아닌 함수 호출 결과가 onClick에 적용된다.
버튼을 클릭할 때가 아니라 컴포넌트가 렌더링 될 때에 alert가 실행되고 그 결과인 undefined가 onClick 에 적용되어 클릭했을 때 아무런 결과도 일어나지 않게 된다.
따라서 이벤트에 함수를 전달할 때는 함수를 호출하는 것이 아닌 아래와 같이 1) 리턴문 안에서 함수를 정의하거나 2) 리턴문 외부에서 함수 정의 후 이벤트에 함수 자체를 전달해야 하며, arrow function 을 사용하여 함수를 정의하여야 해당 컴포넌트가 가진 state에 함수들이 접근할 수 있다.
// 1) 함수 정의하기
return (
<div>
...
<button onClick={() => alert(name)}>Button</button>
...
</div>
);
};
// 2) 함수 자체를 전달하기
const handleClick = () => {
alert(name);
};
return (
<div>
...
<button onClick={handleClick}>Button</button>
...
</div>
);
};
import "./styles.css";
import React, { useState } from "react";
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
};
const handleClick = () => {
alert(name);
};
return (
<div className="App">
<h1>Event handler practice</h1>
<input type="text" value={name} onChange={handleChange}></input>
<button onClick={handleClick}>Button</button>
{/* <button onClick={() => alert(name)}>Button</button> */}
<h3>{name}</h3>
</div>
);
}
export default NameForm;
import React, { useState } from "react";
import "./styles.css";
function SelectExample() {
const [choice, setChoice] = useState("apple");
const fruits = ["apple", "orange", "pineapple", "strawberry", "grape"];
const options = fruits.map((fruit) => {
return <option value={fruit}>{fruit}</option>;
});
console.log(choice);
const handleFruit = (event) => {
setChoice(event.target.value);
//TODO : select tag 가 정상적으로 작동하도록 코드를 완성하세요.
};
return (
<div className="App">
<select onChange={handleFruit}>{options}</select>
<h3>You choose "{choice}"</h3>
</div>
);
}
export default SelectExample;
import React, { useState } from "react";
import "./styles.css";
function App() {
const [showPopup, setShowPopup] = useState(false);
const togglePopup = (event) => {
if(event.target.className === "open") setShowPopup(true);
else setShowPopup(false);
// Pop up 의 open/close 상태에 따라 state 변경
};
return (
<div className="App">
<h1>Fix me to open Pop Up</h1>
{/* 버튼을 클릭했을 때 Pop up 의 open/close 가 작동하도록
button tag를 완성하세요. */}
<button className="open" onClick={togglePopup}>
Open me
</button>
{showPopup ? (
<div className="popup">
<div className="popup_inner">
<h2>Success!</h2>
<button className="close" onClick={togglePopup}>
Close me
</button>
</div>
</div>
) : null}
</div>
);
}
export default App;
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [username, setUsername] = useState("");
const [msg, setMsg] = useState("");
return (
<div className="App">
<div>{username}</div>
<input
type="text"
value={username}
onChange={(event) => setUsername(event.target.value)}
placeholder="여기는 인풋입니다."
className="tweetForm__input--username"
></input>
<div>{msg}</div>
{/* TODO : 위 input과 같이 입력에 따라서 msg state가 변할 수 있게
아래 textarea를 변경하세요. */}
<textarea
placeholder="여기는 텍스트 영역입니다."
className="tweetForm__input--message"
onChange={(event) => setMsg(event.target.value)}
value={msg}
></textarea>
</div>
);
}
React의 개발 방식의 가장 큰 특징은 페이지 단위가 아닌, 컴포넌트 단위로 시작한다는 점!
state, props의 개념에 대해서 이해하고, 실제 프로젝트에 바르게 적용할 수 있다.
React 함수 컴포넌트(React Function Component)에서 state hook을 이용하여 state를 정의 및 변경할 수 있다.
React 컴포넌트(React Component)에 props를 전달할 수 있다.
이벤트 핸들러 함수를 만들고 React에서 이용할 수 있다.
실제 웹 애플리케이션의 컴포넌트를 보고 어떤 데이터가 state이고 props에 적합한지 판단할 수 있다. (중요!!!)
실제 웹 애플리케이션 개발 시 적합한 state와 props의 위치를 스스로 정할 수 있다.
React의 단방향 데이터 흐름(One-way data flow)에 대해 자신의 언어로 설명할 수 있다.
JSX 문법의 기본과 컴포넌트 기반 개발에 대해서 숙지한다.
React Router DOM으로 React에서 SPA(Single-Page Application)을 구현할 수 있다.
state hook을 이용하여, 컴포넌트에서 데이터를 변화시킬 수 있다.
props를 이용하여, 부모 컴포넌트의 데이터를 자식 컴포넌트로 전달할 수 있다.
바람직한 컴포넌트 구조와 state와 props의 위치에 대해 고민한다.