๐ Nomad Coder ReactJS๋ก ์ํ ์น ์๋น์ค ๋ง๋ค๊ธฐ
๊ฐ์๋ ธํธ (2021 Updated ver.)
๋ถ -> ์๊ฐ, ์๊ฐ -> ๋ถ์ผ๋ก ํ์ฐํ๋ ๋ณํ๊ธฐ๋ฅผ ๋ง๋ค์ด๋ณด์.
const [minutes, setMinutes] = React.useState();
const onChange = (e) => {
setMinutes(e.target.value);
}
minutes์๋ ์๋ฌด ๊ฐ๋ ์ ์ธํ์ง ์์๊ณ , onChange
ํจ์๋ฅผ ์ ์ธํด ์ด๋ฒคํธ ๋ฐ์ ์ target(=input)์ ๊ฐ์ state์ ๊ฐ์ผ๋ก setํ๋๋ก ์ค์ ํ๋ค.
<div>
<h1 className="title">Converter</h1>
<label htmlFor="min">Minutes </label>
<input
id="min"
placeholder="Minutes"
type="number"
value={minutes} // state val === input val
onChange={onChange} // onChange: ๋ณํ๊ฐ ์์ ๋๋ง๋ค ๊ฐ์งํ๋ func
/>
<h4>You are going to convert {minutes} to</h4>
<label htmlFor="hrs">Hours </label>
<input id="hrs" placeholder="Hours" type="number" />
</div>
๐ Check Point
JavaScipt๊ฐ ์ ์ ํ ๋จ์ด๋ฅผ JSX์์ ์ฐ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค. ๋์ ์์ฐํ ๋ค๋ฅธ ์ธ์ด์ด๋ค.
JSX์์label
์ ์์ฑ์ผ๋กfor
์ ์ฐ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค. ์ด๋ JS ์ธ์ด์ด๊ธฐ ๋๋ฌธ์ด๋ค. ๋ง์ฐฌ๊ฐ์ง๋กclass
๋ฅผ ์ฐ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
JSX์์ ํด๋น ์์ฑ์ ๋ถ์ฌํ๊ธฐ ์ํด์๋ ์๋์ ๊ฐ์ด ์ ์ฉํด์ผ ํ๋ค.<JS> <JSX> for === HtmlFor class === ClassName
๊ฐ์ฅ ์ฒ์ ์ ์ธํ onChange()
ํจ์๋ฅผ input์ onChange={}
์์ฑ์ ๊ฑธ์ด ์ค์ ํ๋ฉด์, input ๊ฐ์ ๋ณํ๊ฐ ์์ ๋๋ง๋ค state ๊ฐ(=minutes)๊ฐ ํด๋น ๊ฐ์ผ๋ก ์
๋ฐ์ดํธ๋๊ณ ์ด ๊ฐ์ input value๋ก ๋ณด์ฌ์ง๊ฒ ๋๋ค. (input val === state val)
ํค๋ณด๋ ์ ๋ ฅ(์ด๋ฒคํธ ๋ฐ์)
-> target(=input) value ๊ฐ์ง
-> state ๊ฐ์ผ๋ก set
-> input value UI๋ก ํ๊ธฐ
์ ์ฝ๋ ํ๋ก์ฐ๋ฅผ ๋ฐํ์ผ๋ก, ํธํ์ด ๊ฐ๋ฅํ Converter์ ๊ตฌํํ๋ค.
1. ์๊ฐ -> ๋ถ
2. ๋ถ -> ์๊ฐ
<script type="text/babel">
const root = document.getElementById("root")
function App() {
// create State
const [amount, setAmount] = React.useState(0);
const [flip, setFlip] = React.useState(false);
const onChange = (e) => {
// console.log(e.target.value);
setAmount(e.target.value);
}
const reset = () => setAmount(0);
const onflip = () => {
reset();
setFlip(current => !current);
console.log(flip);
} // ํ์ฌ flip๊ฐ์ ๋ฐ๋
return (
(
<div>
<h1 className="title">Converter</h1>
<div>
<label htmlFor="min">Minutes </label>
<input
id="min"
placeholder="Minutes"
type="number"
value={flip ? amount * 60 : amount}
// state val === input val
onChange={onChange} // onChange: ๋ณํ๊ฐ ์์ ๋๋ง๋ค ๊ฐ์งํ๋ func
disabled={flip} // == disabled={flip === true}
// flip์ผ ๋ disabled๋๋๊น flip์ด๋ฉด ์๊ฐ์
๋ ฅ๊ฐ๋ฅ
// ==> flip์ผ๋๋ ์๊ฐ๊ฐ*60์ผ๋ก min ์ธํ์ฐฝ์ ๋ณด์ฌ์ ธ์ผํจ.
// ==> ์๋๋ผ๋ฉด amount ๊ทธ๋๋ก ๋ณด์ฌ์ ธ์ผํจ
/>
</div>
<div>
<label htmlFor="hrs">Hours </label>
<input
id="hrs"
placeholder="Hours"
type="number"
value={flip ? amount : Math.round(amount / 60)}
onChange={onChange}
disabled={!flip} // == disabled={flip === false}
// flip์ด false์ด๋ฉด ์
๋ ฅ๋ถ๊ฐ๋ฅ
// flip์ด true์ผ ๊ฒฝ์ฐ, ์
๋ ฅ๊ฐ ๊ทธ๋๋ก ํ๊ธฐ,
// ์๋๋ผ๋ฉด 60์ผ๋ก ๋๋์ด ํ๊ธฐ
/>
</div>
<button onClick={reset}>Reset</button>
<button onClick={onflip}>{flip ? '->Change to *Mins to Hrs*' : '->Change to *Hrs to Mins*'}</button>
</div>
)
)
}
ReactDOM.render(<App />, root);
</script>
๐ Check Point
- if๋ฌธ ํจ์๋ก ํํํ๋ ๋์ ์ผํญ์ฐ์ฐ์๋ก ๊ฐ๋จํ ์๊ณ ๋ฆฌ์ฆ ๊ตฌํ
- contents๋ฅผ state๋ก ํํ (ex. button ๋ด์ฉ ๋ณ๊ฒฝ)
select
, option
๋ก ์ ํ์ฌํญ์ ์ถ๊ฐํด๋ณด์.
function MinsToHrs() {...}
function KmToMile() {...}
function App() {
const [index, setIndex] = React.useState('0');
const onSelect = (e) => setIndex(e.target.value);
return (
(
<div>
<h1 className="title">Super Converter</h1>
<select value={index} onChange={onSelect}>
<option value="0">Minutes / Hours</option>
<option value="1">km / Mile</option>
</select>
{index === '0' ? <MinsToHrs /> : null}
{index === '1' ? <KmToMile /> : null}
</div>
)
)
}
๐ Check Point
state
๋ฅผ ๋ฐ๊พธ๋ฉด ํด๋น ์ปดํฌ๋ํธ - ์ฐ๊ณ ์ปดํฌ๋ํธ๋ re-rendering ๋๋ค. ๋ฌด์กฐ๊ฑด!- ์์ฑ์ผ๋ก
value
๋ฅผ ๊ฐ์ง ์ ์์ผ๋ฉดonChange
์์ฑ์ ๋ถ์ผ ์ ์๋ค.- ์์ฑ๊ฐ์ ์ปจํธ๋กคํด์ ๋ก์ง์ ๋ง๋๋ ์ฐ์ต์ ํ์.
์์ ์ฝ๋๋ฅผ ์ฐธ๊ณ ํ์ฌ KM -> MILE Converter๋ฅผ ๋ง๋ค์๋ค.
function KmToMile() {
const [amount, setAmount] = React.useState(1);
const [km, setKm] = React.useState(true);
const onChange = (e) => {
setAmount(e.target.value)
};
const reset = () => setAmount('');
const onKm = () => {
reset();
setKm(cur => !cur) // ์ด๊ฒ ๋ฐ๋๋ฉด disabled์ ์ํฅ์ ์ฃผ๋๊น.
}
return (
<div>
<h3>KM to MILE</h3>
<div>
<label htmlFor="km">Km </label>
<input
type="number"
id="km"
value={km ? amount : (amount / 1.609).toFixed(2)}
onChange={onChange}
disabled={!km}
/>
</div>
<div>
<label htmlFor="mile">Mile </label>
<input
type="number"
id="mile"
value={km ? (amount * 1.609).toFixed(2) : amount}
onChange={onChange}
disabled={km}
/>
</div>
<div>
<button onClick={onKm}>{km ? 'Change Mile converter' : 'Change Km Converter'}</button>
</div>
<div>
<button onClick={reset}>reset</button>
</div>
</div>
)
Flow
km๊ฐ์ ์์์ผ๋ก, km ๋ชจ๋์ด๋ฉด mile์ด disabled
-> km value ์ ๋ ฅ
-> target value๋ก amount state ๋ณ๊ฒฝ
-> km ๋ชจ๋์ด๋ฏ๋ก km์นธ amount ๊ทธ๋๋ก ํ๊ธฐ,
mile์นธ *1.609, ์์์ 2์๋ฆฌ๊น์ง ํ๊ธฐ(.toFixed()
)
-> mode change
->onKm()
๋ฐ๋
-> ์ ๋ ฅ๊ฐ / ๊ณ์ฐ๊ฐ ๋ฆฌ์ ,
km ํ์ฌ ๊ฐ์ดtrue
์์ผ๋ฏ๋กfalse
๋ก ๋ณํ
->km === false
์ด๋ฏ๋ก km์นธ disabled, mile์นธ abled
-> mile converter ์ฌ์ฉ๊ฐ๋ฅ
์ด ์ผ๋ จ์ ๊ณผ์ ์ผ๋ก ๋ก์ง์ ๊ฐ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํด ์์ฑํ๋ ์ฐ์ต์ ํ๋ค.
* ์ปดํฌ๋ํธ : App(), MinsToHrs(), KmToMile()
๊ฐ ๋ก์ง์ ๋ฐ๋ผ ์ปดํฌ๋ํธ๋ก ๋ ๋ฆฝ๊ฐ์ฒด๋ก ๋ถํ ํ๋ฉด ์ฌ์ฉ์ฑ๊ณผ ํจ์จ์ด ์์นํ๊ณ , ํ์์ ๋ฐ๋ผ ์ฌ์ฌ์ฉ๋ ๊ฐ๋ฅํ๋ค. ์ฝ๊ฒ ๋งํด ์์๋ฅผ ์ปจํธ๋กคํ๊ธฐ ์ฌ์์ง๋ค.
๋ถํ => ์ ๋ณต
๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ๋ฐฉ๊ธ ๊ตฌํํ ๊ฒ์ฒ๋ผ ํ ํ์ด์ง์ ๋ชฐ๋ ค์๋ค๋ฉด?
๋์ค์ ์ฑ์ด ๊ณ ๋๋ก ๋ฐ์ ํด 1์ต๊ฐ์ ๋จ์ํ์ฐ์ด ํ์ํ๊ฒ ๋๋ค๋ฉด, ์ฐ๋ฆฌ๋ 1์ต๊ฐ์ ์ปดํฌ๋ํธ๋ฅผ ํ ํ์ด์ง์์ ๊ด๋ฆฌํด์ผ ํ๋ค. ์ด๊ฒ์ ๋งค์ฐ ๋นํจ์จ์ ์ด๋ค.
์ปดํฌ๋ํธ๋ ๊ฐ๊ฐ ๋ก์ง์ ๋ฐ๋ผ ๋ถ๋ฅ๋์ด์ ธ์ผ ํ ๊ฒ์ด๊ณ , ๋ถ๋ฆฌ๋ ์ปดํฌ๋ํธ๋ค์ ์ ์ฐ๊ฒฐํด ๋ฐ์ดํฐ ์ ๋ฌ์ด ์ฉ์ดํ๋๋ก ๋ง๋ค์ด์ผ ์ค๋ฅ์๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌํํ ์ ์์ ๊ฒ์ด๋ค.
๋
๋ฆฝ์ ์ผ๋ก ๋ถ๋ฅ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๊ธฐ ์ํด ํ์ํ ๊ฒ์ด Props์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด์ Props๋ฅผ ์์๋ณด์.