React States & props ์ ๊ฐ๋
์ผํ๋ชฐ์์ ์ท์ ์ฃผ๋ฌธํ๋ค๊ณ ํด๋ณด์.
๊ทธ๋ฐ๋ฐ ์ํ๋ ์ท์ ์ฅ๋ฐ๊ตฌ๋์ ๋ด๊ณ ๊ฒฐ์ ๋ฅผ ํ๋ ค๊ณ ๋ณด๋ ๋ค๋ฅธ ์ท์ด ๋ ๋ง์์ ๋๋๊ฒ ์๋๊ฐ...
๋ฐ๋ก ์ฅ๋ฐ๊ตฌ๋์ ๋ด์ ์ท์ ๋นผ๊ณ , ์๋ก์ด ์ท์ ๋ด์ ๊ฒฐ์ ๋ฅผ ํ๋ค.
์ด ์ํฉ์์ ์ฅ๋ฐ๊ตฌ๋์ ๋ด๊ธฐ๋ ์ท์ ๋ฐ๋๊ณ ๋ด๊ฐ ๊ฒฐ์ ํด์ผ ํ ๊ธ์ก๋ ์ฆ๊ฐ์ ์ผ๋ก ๋ณ๊ฒฝ๋๋ค.
์ด๋ฅผ ์ฐ๋ฆฌ๋ ์ฅ๋ฐ๊ตฌ๋์ ์ํ๊ฐ ๋ณํ๋ค๊ณ ๋งํ ์ ์์ผ๋ฉฐ, ๊ฒฐ์ ํ์ด์ง์ ๋ณ๊ฒฝ๋ ์ฅ๋ฐ๊ตฌ๋์ ์ํ๋ฅผ ์ ๋ฌํด์ผ ํ๋ค.
์ด๊ฒ์ด State์ Props์ ๋ํ ํ๋กค๋ก๊ทธ์ด๊ณ , ์ด์ ์์ธํ ์์๋ณด์.
์ฝ๊ธฐ ์ ์ฉ ๊ฐ์ฒด๊ฐ ์๋๋ผ๋ฉด props๋ฅผ ์ ๋ฌ๋ฐ์ ํ์ ์ปดํฌ๋ํธ ๋ด์์ props๋ฅผ ์ง์ ์์ ์ props๋ฅผ ์ ๋ฌํ ์์ ์ปดํฌ๋ํธ์ ๊ฐ์ ์ํฅ์ ๋ฏธ์น ์ ์๊ฒ ๋๋ค. ์ฆ, ๊ฐ๋ฐ์๊ฐ ์๋ํ์ง ์์ side effect๊ฐ ์๊ธฐ๊ฒ ๋๊ณ ์ด๋ React์ ๋จ๋ฐฉํฅ, ํํฅ์ ๋ฐ์ดํฐ ํ๋ฆ ์์น(React is all about one-way data flow down the component hierarchy)์ ์๋ฐฐ๋๋ค.
props๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ์ด 3๋จ๊ณ ์์๋ก ๋๋ ์ ์๋ค.
import "./styles.css";
function Parent() {
return (
<div className="parent">
<h1>I'm the parent</h1>
<Child text={"I'm the eldest child"} />
{/* Child ์ปดํฌ๋ํธ์ ๋ ๋ค๋ฅธ ๋ฌธ์์ด์ props ๋ก ์ ๋ฌํด ๋ณด์ธ์ */}
<Child />
</div>
);
}
function Child(props) {
// console ์ ์ด์ด props ์ ํํ๋ฅผ ์ง์ ํ์ธํ์ธ์.
console.log("props : ", props);
return (
<div className="child">
<p>{props.text}</p>
</div>
);
}
export default Parent;
props๋ฅผ ์ ๋ฌํ๋ ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ์ฌ๋ ํ๊ทธ์ ๋ซ๋ ํ๊ทธ์ ์ฌ์ด์ value๋ฅผ ๋ฃ์ด ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
์ด ๊ฒฝ์ฐ props.children์ ์ด์ฉํ๋ฉด ํด๋น value์ ์ ๊ทผํ์ฌ ์ฌ์ฉํ ์ ์๋ค.
import "./styles.css";
const App = () => {
const itemOne = "React๋ฅผ";
const itemTwo = "๋ฐฐ์ฐ๊ณ ์์ต๋๋ค.";
return (
<div className="App">
{/* Learn ์ปดํฌ๋ํธ์ itemOne ๊ณผ itemTwo ๋ฅผ
props ๋ก ์ ๋ฌํ์ธ์ */}
<Learn>{itemOne}</Learn>
<Learn>{itemTwo}</Learn>
</div>
);
};
const Learn = (props) => {
// ์ ๋ฌ๋ฐ์ props ๋ฅผ ์๋ <div> tag ์ฌ์ด์ ์ฌ์ฉํ์ฌ
// "React๋ฅผ ๋ฐฐ์ฐ๊ณ ์์ต๋๋ค" ๋ผ๋ ๋ฌธ์ฅ์ด ๋ ๋๋ง๋๋๋ก ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ์ธ์
return <div className="Learn">
<p>{props.children}</p></div>;
};
export default App;
์ ํ๋ฆฌ์ผ์ด์ ์ "์ํ"
State & Props ์์์์ state๋ Toggle Switch๋ Counter์ฒ๋ผ ์ปดํฌ๋ํธ ๋ด๋ถ์์ ๋ณํ ์ ์๋ ๊ฐ์ด๋ผ๊ณ ํ๋ค.
์ค์ ์ ํ๋ฆฌ์ผ์ด์
์์๋ ๋ฌด์์ด "์ํ"๋ผ๊ณ ํ ์ ์์๊น? ์ผํ๋ชฐ ์ฅ๋ฐ๊ตฌ๋๋ฅผ ์๋ก ๋ค์ด๋ณด๊ฒ ๋ค.
์ฌ์ฉ์๋ ๊ตฌ๋งคํ ๋ฌผ๊ฑด๊ณผ ๋น์ฅ์ ๊ตฌ๋งคํ์ง ์์ ๋ฌผ๊ฑด์ ์ฒดํฌ๋ฐ์ค์ ์ฒดํฌํ์ฌ ๊ตฌ๋ถ ์ง๋๋ค.
์ด๋ฅผ ์ฅ๋ฐ๊ตฌ๋ ๋ด์์์ ์ํ๋ก ๊ตฌ๋ถํด ๋ณธ๋ค๋ฉด check ๋ ์ํ
์ check ๋์ง ์์ ์ํ
์ด๋ค.
์ฒดํฌ๋ฐ์ค๋ฅผ ์ฝ๋๋ก ๊ตฌํํด ๋ณด๋ฉด ์๋์ ๊ฐ๋ค.
์๋ ์์์์๋ ๋จ์ํ ์ฒดํฌ๋ ์ํ์ ๋ฐ๋ผ ๋ณด์ด๋ ๊ธ์จ๊ฐ ๋ฌ๋ผ์ง์ง๋ง,
์ด๋ฅผ ์ผํ๋ชฐ์ ์ ์ฉํ๋ฉด ์ฒดํฌ ์ฌ๋ถ์ ๋ฐ๋ผ ๊ตฌ๋งคํ ๋ฌผ๊ฑด์ ๊ฐ์๋ ๊ตฌ๋งค ๊ธ์ก์ด ๋ณ๊ฒฝ๋๊ณ , ์ด์ ๋ฐ๋ผ ์ฌ์ฉ์์ ํ๋ฉด ๋ํ ๋ฌ๋ผ์ง๋ค.
์ด์ฒ๋ผ ์ปดํฌ๋ํธ ๋ด์์ ๋ณํ ์ ์๋ ๊ฐ, ์ฆ ์ํ๋ React state๋ก ๋ค๋ค์ผ ํ๋ค.
import React, { useState } from "react";
import "./styles.css";
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
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;
React์์๋ state๋ฅผ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ ์ค ํ๋๋ก useState
๋ผ๋ ํน๋ณํ ํจ์๋ฅผ ์ ๊ณตํ๋ค.
์ด ํจ์์ ์ฌ์ฉ ๋ฐฉ๋ฒ๊ณผ ์๋ ๋ฐฉ์์ ์์ ์ฒดํฌ๋ฐ์ค ์๋ก ๋ค์ด ์ดํด๋ณด๊ฒ ๋ค.
useState
๋ฅผ ์ด์ฉํ๊ธฐ ์ํด์๋, React์์ import
ํค์๋๋ก useState
๋ฅผ ๋ถ๋ฌ์์ผ ํ๋ค.
import { useState } from "react";
์ดํ useState๋ฅผ ์ปดํฌ๋ํธ ์์์ ํธ์ถํด ์ค๋ค.
useState๋ฅผ ํธ์ถํ๋ค๋ ๊ฒ์ "state"๋ผ๋ ๋ณ์๋ฅผ ์ ์ธํ๋ ๊ฒ๊ณผ ๊ฐ์ผ๋ฉฐ, ์ด ๋ณ์์ ์ด๋ฆ์ ์๋ฌด ์ด๋ฆ์ผ๋ก ์ง์ด๋ ๋๋ค.
์ผ๋ฐ์ ์ธ ๋ณ์๋ ํจ์๊ฐ ๋๋ ๋ ์ฌ๋ผ์ง์ง๋ง, state ๋ณ์๋ React์ ์ํด ํจ์๊ฐ ๋๋๋ ์ฌ๋ผ์ง์ง ์๋๋ค.
๋ฌธ๋ฒ์ ์ผ๋ก ๋ณด๋ฉด ์๋ ์์์ isChecked
, setIsChecked
๋ useState
์ ๋ฆฌํด๊ฐ์ ๊ตฌ์กฐ ๋ถํด ํ ๋นํ ๋ณ์์ด๋ค.
function CheckboxExample() {
// ์๋ก์ด state ๋ณ์๋ฅผ ์ ์ธํ๊ณ , ์ฌ๊ธฐ์๋ ์ด๊ฒ์ isChecked๋ผ ๋ถ๋ฅด๊ฒ ์ต๋๋ค.
const [isChecked, setIsChecked] = useState(false); // 1๋ฒ
//...
// 1๋ฒ ์ฝ๋๋ฅผ ํ์ด์ฐ๋ฉด, 2๋ฒ ์ฝ๋์ ๊ฐ์ต๋๋ค.
const stateHookArray = useState(false); // 2๋ฒ
const isChecked = stateHookArray[0];
const setIsChecked = stateHookArray[1];
}
useState
๋ฅผ ํธ์ถํ๋ฉด ๋ฐฐ์ด์ ๋ฐํํ๋๋ฐ, ๋ฐฐ์ด์ 0๋ฒ์งธ ์์๋ ํ์ฌ state ๋ณ์์ด๊ณ , 1๋ฒ์งธ ์์๋ ์ด ๋ณ์๋ฅผ ๊ฐฑ์ ํ ์ ์๋ ํจ์์ด๋ค. useState
์ ์ธ์๋ก ๋๊ฒจ์ฃผ๋ ๊ฐ์ state์ ์ด๊น๊ฐ์ด๋ค.
// useState ์๋ ์ฝ๋
const [state ์ ์ฅ ๋ณ์, state ๊ฐฑ์ ํจ์] = useState(์ํ ์ด๊ธฐ ๊ฐ);
์๋ ์ฝ๋๋ฅผ ์ค์ ์ฝ๋๋ก ์์ฑํด ๋ณด์.
// useState ๋ฌธ๋ฒ ์์
function CheckboxExample() {
const [isChecked, setIsChecked] = useState(false);
// const [state ์ ์ฅ ๋ณ์, state ๊ฐฑ์ ํจ์] = useState(state ์ด๊น๊ฐ);
isChecked
: state๋ฅผ ์ ์ฅํ๋ ๋ณ์setIsChecked
: state isChecked
๋ฅผ ๋ณ๊ฒฝํ๋ ํจ์useState
: state hookfalse
: state ์ด๊น๊ฐ์ด state ๋ณ์์ ์ ์ฅ๋ ๊ฐ์ ์ฌ์ฉํ๋ ค๋ฉด JSX ์๋ฆฌ๋จผํธ ์์ ์ง์ ๋ถ๋ฌ์ ์ฌ์ฉํ๋ฉด ๋๋ค.
์ฌ๊ธฐ์๋ isChecked
๊ฐ boolean ๊ฐ์ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ true
or false
์ฌ๋ถ์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋ณด์ด๋๋ก ์ผํญ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ค.
// JSX์์ ์ผํญ์ฐ์ฐ์ ์ฌ์ฉ ์์
<span>{isChecked ? "Checked!!" : "Unchecked"}</span>
state๋ฅผ ๊ฐฑ์ ํ๋ ค๋ฉด state ๋ณ์๋ฅผ ๊ฐฑ์ ํ ์ ์๋ ํจ์์ธ setIsChecked
๋ฅผ ํธ์ถํ๋ค.
์ด๋ฒ ์์์ ๊ฒฝ์ฐ, input[type=checkbox]
JSX ์๋ฆฌ๋จผํธ์ ๊ฐ ๋ณ๊ฒฝ์ ๋ฐ๋ผ์ isChecked
๊ฐ ๋ณ๊ฒฝ๋์ด์ผ ํ๋ค.
๋ธ๋ผ์ฐ์ ์์
checked
๋ก ๊ฐ์ด ๋ณ๊ฒฝ๋์๋ค๋ฉด, React์isChecked
๋ ๋ณ๊ฒฝ๋์ด์ผํ๋ค !
onChange
์ด๋ฒคํธ๊ฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ ํจ์์ธ handleChecked
๋ฅผ ํธ์ถํ๊ณ , ์ด ํจ์๊ฐ setIsChecked
๋ฅผ ํธ์ถํ๊ฒ ๋๋ค. setIsChecked
๊ฐ ํธ์ถ๋๋ฉด ํธ์ถ๋ ๊ฒฐ๊ณผ์ ๋ฐ๋ผ isChecked
๋ณ์๊ฐ ๊ฐฑ์ ๋๋ฉฐ, React๋ ์๋ก์ด isChecked
๋ณ์๋ฅผ CheckboxExample
์ปดํฌ๋ํธ์ ๋๊ฒจ ํด๋น ์ปดํฌ๋ํธ๋ฅผ ๋ค์ ๋ ๋๋ง ํ๋ค.import React, { useState } from "react";
import "./styles.css";
function CheckboxExample() {
console.log("rerendered?");
const [isChecked, setIsChecked] = useState(false);
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;
React์ ์ด๋ฒคํธ ์ฒ๋ฆฌ(์ด๋ฒคํธ ํธ๋ค๋ง; Event handling) ๋ฐฉ์์ DOM์ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋ฐฉ์๊ณผ ์ ์ฌํ๋ค.
๋จ, ๋ช ๊ฐ์ง ๋ฌธ๋ฒ ์ฐจ์ด๊ฐ ์๋ค.
์๋ฅผ ๋ค์ด HTML์์ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋ฐฉ์์ด ์๋์ ๊ฐ๋ค๋ฉด,
<button onclick="handleEvent()">Event</button>
React์ ์ด๋ฒคํธ ์ฒ๋ฆฌํ๋ ๊ธฐ๋ณธ ๋ฐฉ์์ ์๋์ ๊ฐ๋ค.
<button onClick={handleEvent}>Event</button>
<input>
<textarea>
<select>
์ ๊ฐ์ ํผ(Form) ์๋ฆฌ๋จผํธ๋ ์ฌ์ฉ์์ ์
๋ ฅ๊ฐ์ ์ ์ดํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
React์์๋ ์ด๋ฌํ ๋ณ๊ฒฝ๋ ์ ์๋ ์
๋ ฅ๊ฐ์ ์ผ๋ฐ์ ์ผ๋ก ์ปดํฌ๋ํธ์ state๋ก ๊ด๋ฆฌํ๊ณ ์
๋ฐ์ดํธํ๋ค.
onChange
์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด e.target.value
๋ฅผ ํตํด ์ด๋ฒคํธ ๊ฐ์ฒด์ ๋ด๊ฒจ์๋ input
๊ฐ์ ์ฝ์ด์ฌ ์ ์๋ค.
์ปดํฌ๋ํธ return ๋ฌธ ์์ input
ํ๊ทธ์ value
์ onChange
๋ฅผ ๋ฃ์ด์ฃผ์๋ค.
onChange
๋input
์ ํ ์คํธ๊ฐ ๋ฐ๋ ๋๋ง๋ค ๋ฐ์ํ๋ ์ด๋ฒคํธ์ด๋ค.
์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด handleChange
ํจ์๊ฐ ์๋ํ๋ฉฐ, ์ด๋ฒคํธ ๊ฐ์ฒด์ ๋ด๊ธด input
๊ฐ์ setState
๋ฅผ ํตํด ์๋ก์ด state๋ก ๋ณ๊ฒฝํ๋ค.
function NameForm() {
const [name, setName] = useState("");
const handleChange = (e) => {
setName(e.target.value);
}
return (
<div>
<input type="text" value={name} onChange={handleChange}></input>
<h1>{name}</h1>
</div>)
};
onClick
์ด๋ฒคํธ๋ ๋ง ๊ทธ๋๋ก ์ฌ์ฉ์๊ฐ ํด๋ฆญ์ด๋ผ๋ ํ๋์ ํ์์ ๋ ๋ฐ์ํ๋ ์ด๋ฒคํธ์ด๋ค.
๋ฒํผ์ด๋ <a>
tag๋ฅผ ํตํ ๋งํฌ ์ด๋ ๋ฑ๊ณผ ๊ฐ์ด ์ฃผ๋ก ์ฌ์ฉ์์ ํ๋์ ๋ฐ๋ผ, ์ฑ์ด ๋ฐ์ํด์ผ ํ ๋ ์์ฃผ ์ฌ์ฉํ๋ ์ด๋ฒคํธ์ด๋ค.
๊ทธ๋ผ ์์ onChange
์์์ ๋ฒํผ์ ์ถ๊ฐํ์ฌ ๋ฒํผ ํด๋ฆญ ์,
input
tag์ ์
๋ ฅํ ์ด๋ฆ์ด alert์ ํตํด ์๋ฆผ ์ฐฝ์ด ํ์
๋๋๋ก ์ฝ๋๋ฅผ ์ถ๊ฐํด ๋ณด๊ฒ ๋ค.
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(ํจ์๋ ๋ฆฌํด ๊ฐ์ด ์์ ๋ undefined๋ฅผ ๋ฐํํ๋ค.)๊ฐ
onClick์ ์ ์ฉ๋์ด ํด๋ฆญํ์ ๋ ์๋ฌด๋ฐ ๊ฒฐ๊ณผ๋ ์ผ์ด๋์ง ์๋๋ค.
๋ฐ๋ผ์ 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;
Action item - select
// select tag๋ ์ฌ์ฉ์๊ฐ drop down ๋ชฉ๋ก์ ์ด์ด ๊ทธ์ค ํ ๊ฐ์ง ์ต์
์ ์ ํํ๋ฉด, ์ ํ๋ ์ต์
์ด state ๋ณ์์ ๋ณ๊ฒฝ๋๋ค.
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) => {
//TODO : select tag ๊ฐ ์ ์์ ์ผ๋ก ์๋ํ๋๋ก ์ฝ๋๋ฅผ ์์ฑํ์ธ์.
setChoice(event.target.value);
};
return (
<div className="App">
<select onChange={handleFruit}>{options}</select>
<h3>You choose "{choice}"</h3>
</div>
);
}
export default SelectExample;
Action item - Pop up
// Pop up ์ญ์ Pop up์ open๊ณผ close๋ฅผ state๋ฅผ ํตํด ๊ด๋ฆฌํ ์ ์๋ค.
import React, { useState } from "react";
import "./styles.css";
function App() {
const [showPopup, setShowPopup] = useState(false);
const togglePopup = () => {
// Pop up ์ open/close ์ํ์ ๋ฐ๋ผ
// ํ์ฌ state ๊ฐ ์
๋ฐ์ดํธ ๋๋๋ก ํจ์๋ฅผ ์์ฑํ์ธ์.
setShowPopup(!showPopup);
};
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;
React Twittler State & Props ์คํ๋ฆฐํธ์์๋ ์ง๊ธ๊น์ง ๋ฐฐ์ด
state, props๋ฅผ ํ์ฉํ์ฌ ์ ์ parkhacker์ Twittler์์์ ํธ์ ์ ์ก ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค.
์ด๋ฒ ์คํ๋ฆฐํธ์ ํต์ฌ์ ํธ์ ์ถ๊ฐ ๋ฐ ์ถ๊ฐ๋ ํธ์ ์กฐํ ๊ธฐ๋ฅ ๊ตฌํ์ด๋ค.
์ด ๊ธฐ๋ฅ ๊ตฌํ์ ์ํด์ ์ด๋ค ์ปดํฌ๋ํธ์ ์ด๋ค state๊ฐ ํ์ํ๊ณ , ์ด state๋ฅผ ์ด๋ป๊ฒ ๋ณํ์ํฌ ๊ฒ์ธ์ง ๊ณ ๋ฏผํด ๋ณด์.
โ React Router ์ค์น
โ ์์ธ ์ปดํฌ๋ํธ ๊ตฌํํ๊ธฐ
โ Sidebar ์ปดํฌ๋ํธ (Sidebar.js)
โ Footer ์ปดํฌ๋ํธ (Footer.js)
โ Tweet ์ปดํฌ๋ํธ (Tweet.js)
โ ํ์ด์ง ์ปดํฌ๋ํธ ๊ตฌํํ๊ธฐ
โ About ์ปดํฌ๋ํธ (About.js)
โ MyPage ์ปดํฌ๋ํธ (MyPage.js)
โ Tweets ์ปดํฌ๋ํธ (Tweets.js)
โ React Router ์ ์ฉํ๊ธฐ
โ React Router ์ปดํฌ๋ํธ ์ ์ฉ
โ React Router๋ก SPA ๊ตฌํํ๊ธฐ
โ State, Props ํ์ฉ ํธ์ ์ ์ก Form ๋ง๋ค๊ธฐ
โ Tweets.js ํธ์ ์ ์ก Form ํ ์คํธ
// TODO : useState๋ฅผ react๋ก ๋ถํฐ import ํฉ๋๋ค.
import React from "react";
import Footer from "../Footer";
import Tweet from "../Components/Tweet";
import "./Tweets.css";
import dummyTweets from "../static/dummyData";
import { useState } from "react";
const Tweets = () => {
// TODO : ์๋ก ํธ์์ ์์ฑํ๊ณ ์ ์กํ ์ ์๊ฒ useState๋ฅผ ์ ์ ํ ํ์ฉํ์ธ์.
// -> useState๋ฅผ ๋ช ๊ณณ์ ์ด๋ป๊ฒ ์ฌ์ฉํ ์ง ์๊ฐํ๋ค.
const [newComment, setNewComment] = useState(dummyTweets);
const [user, setUser] = useState("parkhacker");
const [msg, setMsg] = useState("");
const handleButtonClick = (event) => {
// TODO : Tweet button ์๋ฆฌ๋จผํธ ํด๋ฆญ์ ์๋ํ๋ ํจ์๋ฅผ ์์ฑํ์ธ์.
// ํธ์ ์ ์ก์ด ๊ฐ๋ฅํ๊ฒ ์์ฑํด์ผ ํฉ๋๋ค.
// -> ๋ฒํผ์ ๋๋ ์ ๋, ์
๋ ฅํ data ๊ฐ์ด dummyTweets์ ์ถ๊ฐ๋์ด์ผ ํ๋ค.
// -> tweet๋ค์ด ๋ชจ์ฌ์๋ ์ปดํฌ๋ํธ ์์ ๋ด๊ฐ ์
๋ ฅํ tweet์ ์ปดํฌ๋ํธํํด์ ๋ฃ์ด์ค๋ค.
// -> useState ์ฌ์ฉ, spread ๋ฌธ๋ฒ์ผ๋ก ๋ฐฐ์ด์ ์ถ๊ฐ
const tweet = {
...dummyTweets,
id: dummyTweets.length,
username: user,
content: msg,
createdAt: new Date().toLocaleDateString("ko-kr"),
updatedAt: new Date().toLocaleDateString("ko-kr"),
};
setNewComment([tweet, ...newComment]);
};
const handleChangeUser = (event) => {
// TODO : Tweet input ์๋ฆฌ๋จผํธ์ ์
๋ ฅ ์ ์๋ํ๋ ํจ์๋ฅผ ์์ฑํ์ธ์.
setUser(event.target.value);
};
const handleChangeMsg = (event) => {
// TODO : Tweet textarea ์๋ฆฌ๋จผํธ์ ์
๋ ฅ ์ ์๋ํ๋ ํจ์๋ฅผ ์์ฑํ์ธ์.
setMsg(event.target.value);
};
return (
<React.Fragment>
<div className="tweetForm__container">
<div className="tweetForm__wrapper">
<div className="tweetForm__profile">
<img src="https://randomuser.me/api/portraits/men/98.jpg" />
</div>
<div className="tweetForm__inputContainer">
<div className="tweetForm__inputWrapper">
<div className="tweetForm__input">
{/* -> ํผ ์๋ฆฌ๋จผํธ์์ ๋ณ๊ฒฝ๋ ์ ์๋ ์
๋ ฅ ๊ฐ์ onChange ์ด๋ฒคํธ๋ก state ๊ด๋ฆฌ & ์
๋ฐ์ดํธ */}
<input
type="text"
value={user}
placeholder="your username here.."
className="tweetForm__input--username"
onChange={handleChangeUser}
></input>
<textarea
className="tweetForm__input--message"
value={msg}
placeholder="your message here.."
onChange={handleChangeMsg}
/>
</div>
<div className="tweetForm__count" role="status">
<span className="tweetForm__count__text">
{/* TODO : ํธ์ ์ด ๊ฐ์๋ฅผ ๋ณด์ฌ์ค ์ ์๋ Counter๋ฅผ ์์ฑํ์ธ์. */}
{/* -> dummyTweets๊ฐ ์๋ useState๊ฐ ์ํ ๊ด๋ฆฌํ๋ element(๋ฐฐ์ด)๊ฐ ์์ผ ํ๋ค. */}
{`Total: ${newComment.length}`}
</span>
</div>
</div>
<div className="tweetForm__submit">
<div className="tweetForm__submitIcon"></div>
{/* TODO : ์์ฑํ ํธ์์ ์ ์กํ ์ ์๋ button ์๋ฆฌ๋จผํธ๋ฅผ ์์ฑํ์ธ์. */}
{/* -> ์ฌ์ฉ์๊ฐ ํด๋ฆญ์ด๋ผ๋ ํ๋์ ํ์์ ๋ ๋ฐ์ํ๋ ์ด๋ฒคํธ์ด๋ฏ๋ก onClick */}
<button
className="tweetForm__submitButton"
onClick={handleButtonClick}
>
submit
</button>
</div>
</div>
</div>
</div>
<div className="tweet__selectUser"></div>
<ul className="tweets">
{/* TODO : ํ๋์ ํธ์์ด ์๋๋ผ, ์ฃผ์ด์ง ํธ์ ๋ชฉ๋ก(dummyTweets) ๊ฐฏ์์ ๋ง๊ฒ ๋ณด์ฌ์ค์ผ ํฉ๋๋ค. */}
{/* -> `Total: ${newComment.length}`๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ๊ฐ์ element(๋ฐฐ์ด)๋ฅผ ๊ฐ์ ธ์ map์ผ๋ก ๋ฟ๋ ค์ค๋ค. */}
{newComment.map((el) => {
return <Tweet tweet={el} />;
})}
</ul>
<Footer />
</React.Fragment>
);
};
export default Tweets;
import React from "react";
import Footer from "../Footer";
import Tweet from "../Components/Tweet";
import "./MyPage.css";
import dummyTweets from "../static/dummyData";
const MyPage = () => {
// TODO : ์ฃผ์ด์ง ํธ์ ๋ชฉ๋ก(dummyTweets)์ค ํ์ฌ ์ ์ ธ์ธ parkhacker์ ํธ์๋ง ๋ณด์ฌ์ค์ผ ํฉ๋๋ค.
// -> dummyTweets ๋ฐฐ์ด์์ filter๋ก parkhacker ๊ฐ๋ง ์ถ์ถ
const filteredTweets = dummyTweets.filter((tweet) => {
return tweet.username === "parkhacker";
});
return (
<section className="myInfo">
<div className="myInfo__container">
<div className="myInfo__wrapper">
<div className="myInfo__profile">
<img src={filteredTweets[0].picture} />
</div>
<div className="myInfo__detail">
<p className="myInfo__detailName">
{filteredTweets[0].username} Profile
</p>
<p>28 ํ๋ก์ 100 ํ๋ก์</p>
</div>
</div>
</div>
<ul className="tweets__mypage">
<Tweet tweet={filteredTweets[0]} />
{/* TODO : ์ฃผ์ด์ง ํธ์ ๋ชฉ๋ก(dummyTweets)์ค ํ์ฌ ์ ์ ธ์ธ parkhacker์ ํธ์๋ง ๋ณด์ฌ์ค์ผ ํฉ๋๋ค. */}
</ul>
<Footer />
</section>
);
};
export default MyPage;