[React] ์ด๋ฒคํธ ์ฒ๋ฆฌ & Controlled Component & React ๋ฐ์ดํฐ ํ๋ฆ
๐๋ฆฌ์กํธ ๊ฐ๋
๐์ด๋ฒคํธ ์ฒ๋ฆฌ( Event handling )
React ์์ ์ด๋ฒคํธ๋ ์๋ฌธ์ ๋์ ์นด๋ฉ ์ผ์ด์ค๋ฅผ ์ฌ์ฉ
JSX๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ์์ด์ด ์๋ ํจ์๋ก ์ด๋ฒคํธ ์ฒ๋ฆฌ ํจ์๋ฅผ ์ ๋ฌ
<button onclick="handleEvent()">Event</button> // html
<button onClick={handleEvent}>Event</button> // react
๐ onChange
ํผ(Form) ์๋ฆฌ๋จผํธ (<input><textarea><select>) ๋ ์ ๋ ฅ๊ฐ์ ์ ์ดํ๋ ๋ฐ ์ฌ์ฉ
๋ณ๊ฒฝ๋ ์ ์๋ ์ ๋ ฅ๊ฐ -> ์ปดํฌ๋ํธ์ state๋ก ๊ด๋ฆฌ
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value); // onChange ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด e.target.value๋ฅผ ํตํด input ๊ฐ์ ์ฝ์ด์ด
}
return (
<div>
{/* inputํ๊ทธ ์์ value์ onChange(ํ
์คํธ๊ฐ ๋ฐ๋ ๋ ๋ฐ์ํ๋ ์ด๋ฒคํธ)๋ฅผ ๋ฃ์ด์ค
์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด handleChange ํจ์๊ฐ ์๋ ์๋ก์ด state๋ก ๊ฐฑ์ */}
<input type="text" value={name} onChange={handleChange}></input>
<h1>{name}</h1>
</div>
)
};
onChange ์ค์ต
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);
};
์คํ๊ฒฐ๊ณผ
์ต์ ์ ์ ํํ ๋๋ง๋ค text๊ฐ ๋ณ๊ฒฝ๋จ์ด ํ์ธ ๊ฐ๋ฅํ๋ค
๐ onClick
์ฌ์ฉ์๊ฐ ํด๋ฆญ์ด๋ผ๋ ํ๋์ ํ์์ ๋ ๋ฐ์ํ๋ ์ด๋ฒคํธ
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
{/* input tag ์ ์
๋ ฅํ ์ด๋ฆ์ด alert์ ํตํด ์๋ฆผ ์ฐฝ์ด ํ์
๋๋๋ก ์ฝ๋๋ฅผ ์ถ๊ฐ */}
<input type="text" value={name} onChange={handleChange}></input>
<button onClick={alert(name)}>Button</button>
<h1>{name}</h1>
</div>
);
};
onClick ์ด๋ฒคํธ์ ํจ์๋ฅผ ์ ๋ฌํ ๋๋ ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒ์ด ์๋๋ผ ์๋์ ๊ฐ์ด ๋ฆฌํด๋ฌธ ์์์ ํจ์๋ฅผ ์ ์ํ๊ฑฐ๋
๋ฆฌํด๋ฌธ ์ธ๋ถ์์ ํจ์๋ฅผ ์ ์ ํ ์ด๋ฒคํธ์ ํจ์ ์์ฒด๋ฅผ ์ ๋ฌ
// ํจ์ ์ ์ํ๊ธฐ
return (
<div>
...
<button onClick={() => alert(name)}>Button</button>
...
</div>
);
};
// ํจ์ ์์ฒด๋ฅผ ์ ๋ฌํ๊ธฐ
const handleClick = () => {
alert(name);
};
return (
<div>
...
<button onClick={handleClick}>Button</button>
...
</div>
);
};
onClick ์ค์ต
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;
์คํ ๊ฒฐ๊ณผ ๋๊ฐ์ง ๋ฒํผ ๋ชจ๋ alert์ด ๋จ๋ ๊ฒ์ด ํ์ธ ๊ฐ๋ฅํ๋ค
popup ์ค์ต
import React, { useState } from "react";
import "./styles.css";
function App() {
const [showPopup, setShowPopup] = useState(false);
const togglePopup = (e) => {
// Pop up ์ open/close ์ํ์ ๋ฐ๋ผ
// ํ์ฌ state ๊ฐ ์
๋ฐ์ดํธ ๋๋๋ก ํจ์๋ฅผ ์์ฑํ์ธ์.
if (showPopup === false) {
setShowPopup(true);
} else setShowPopup(false);
};
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;
์คํ๊ฒฐ๊ณผ
๐Controlled Component
๋ฆฌ์กํธ๊ฐ state์ ํต์ ํ ์ ์๋ ์ปดํฌ๋ํธ๋ฅผ ์ปจํธ๋กค ์ปดํฌ๋ํธ๋ผ๊ณ ํ๋ค.
controlled component ์ค์ต
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={""}
></textarea>
</div>
);
}
์คํ ๊ฒฐ๊ณผ
๐ React ๋ฐ์ดํฐ ํ๋ฆ
ํ์ด์ง ๋จ์ x -> ์ปดํฌ๋ํธ ๋จ์ o
์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ณ ๋ค์ ํ์ด์ง๋ฅผ ์กฐ๋ฆฝ
์ปดํฌ๋ํธ๋ ์ํฅ์(bottom-up)์ผ๋ก ์ ์ -> ํ ์คํธ๊ฐ ์ฝ๊ณ ํ์ฅ์ฑ์ด ์ข๋ค
ํธ๋ฆฌ๊ตฌ์กฐ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ ๋ค
๋ฐ์ดํฐ๋ฅผ ์ด๋์ ๋์ง ๊ฒฐ์
์ปดํฌ๋ํธ๋ ์ปดํฌ๋ํธ ๋ฐ๊นฅ์์ props๋ฅผ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ๋ง์น ์ธ์ ํน์ ์์ฑ ์ฒ๋ผ
์ ๋ฌ๋ฐ์ ์ ์๋ค.
๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ์ฃผ์ฒด -> ๋ถ๋ชจ ์ปดํฌ๋ํธ : ๋ฐ์ดํฐ ํ๋ฆ์ด ํํฅ์(top-down)์์ ์๋ฏธ
๋จ๋ฐฉํฅ ๋ฐ์ดํฐ ํ๋ฆ(one-way data flow)
์ปดํฌ๋ํธ๋ props๋ฅผ ํตํด ์ ๋ฌ๋ฐ์ ๋ฐ์ดํฐ๊ฐ ์ด๋์ ์๋์ง ์ ์ ์์
์ํ๋ ์ต์ํํ๋ ๊ฒ์ด ์ข๋ค(๋ณต์ก์ฑ ๋๋ฌธ)
- ๋ถ๋ชจ๋ก๋ถํฐ props๋ฅผ ํตํด ์ ๋ฌ๋ฉ๋๊น? ๊ทธ๋ฌ๋ฉด ํ์คํ state๊ฐ ์๋๋๋ค.
- ์๊ฐ์ด ์ง๋๋ ๋ณํ์ง ์๋์? ๊ทธ๋ฌ๋ฉด ํ์คํ state๊ฐ ์๋๋๋ค.
- ์ปดํฌ๋ํธ ์์ ๋ค๋ฅธ state๋ props๋ฅผ ๊ฐ์ง๊ณ ๊ณ์ฐ ๊ฐ๋ฅํ๊ฐ์? ๊ทธ๋ ๋ค๋ฉด state๊ฐ ์๋๋๋ค.
์ํ๋ฅผ ์ด๋์ ์์น์์ผ์ผ ํ๋์ง ์ดํด๋ด์ผ ํ๋ค
A component , B component -> parent component ๋ผ๋ฉด, parent ์ ์ํ๋ฅผ ์์น