State
Counter
버튼을 누르면 counter가 하나씩 증가하는 페이지를 구성하는 경우,
첫 렌더링 이후 계속해서 값을 띄우기 위해 render() 함수를 만들어 반복 실행했다
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = document.getElementById("root");
let counter = 0;
function countUp() {
counter = counter + 1;
render()
}
function render() {
ReactDOM.render(<Container/>, root);
}
const Container = () => <div>
<h3>Total clicks: { counter }</h3>
<button onClick={ countUp }>Click me</button>
</div>
ReactDOM.render(<Container/>, root);
</script>
</html>
여기저기서 render() 함수를 호출하는 것은 매우 비효율적인데,,
useState를 활용하면 데이터와, 데이터의 업데이트 함수를 바로 생성할 수 있다
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function App () {
const [counter, setCounter] = React.useState(0);
const onClick = () => {
setCounter((current) => current + 1);
}
return(
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
}
ReactDOM.render(<App/>, root);
</script>
</html>
이전 값을 활용해 State를 변경하려면 setState()함수에 직접 넣어줘도 되지만,,
setCounter(counter+1);
State가 다른 곳에서 변경될 수도 있기 때문에 current 함수로 처리하는 것이 안전하다!
setCounter((current) => current + 1);
Super Converter
JSX 상에서는 일부 HTML 코드를 변환해 사용해야 한다
ex) class -> className / for -> htmlFor
Input과 State를 활용해 단위 변환기를 만들어보자!
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function App () {
const [minutes, setMinutes] = React.useState();
const onChange = (event) => {
setMinutes(event.target.value);
};
return(
<div>
<h1>Super Converter</h1>
<label htmlFor="minutes">Minutes</label>
<input
value={minutes}
id="minutes"
placeholder="Minutes"
type="number"
onChange={onChange}
/>
<h4>You want to convert {minutes}</h4>
<label htmlFor="hours">Hours</label>
<input id="hours" placeholder="Hours" type="number" />
</div>
);
}
ReactDOM.render(<App/>, root);
</script>
</html>
- input에서 받는 value를 state와 연결
- 함수를 생성해 onChange에 연결
- 매개변수 event로 target.value(현재 입력값) 연결
- 해당 값을 setState()에 넣어 실시간 입력값을 state로 업데이트
function App () {
const [minutes, setMinutes] = React.useState();
const onChange = (event) => {
setMinutes(event.target.value);
};
const reset = () => {
setMinutes(0);
}
return(
<div>
<h1>Super Converter</h1>
<div>
<label htmlFor="minutes">Minutes</label>
<input
value={minutes}
id="minutes"
placeholder="Minutes"
type="number"
onChange={onChange}
/>
<h4>You want to convert {minutes}</h4>
</div>
<div>
<label htmlFor="hours">Hours</label>
<input
value={Math.round(minutes / 60)}
id="hours"
placeholder="Hours"
type="number"
disabled
/>
</div>
<button onClick={reset}>Reset</button>
</div>
);
}
ReactDOM.render(<App/>, root);
Hours의 input에서 state를 value로 받아와 60으로 나눠 Converter 완성!
Flip 버튼으로 시간/분 변환을 반대로 바꿔볼 것이다
function App () {
const [amount, setAmount] = React.useState();
const [flipped, setFlipped] = React.useState(false);
const onChange = (event) => {
setAmount(event.target.value);
};
const reset = () => setAmount(0);
const onFlip = () => {
reset();
setFlipped((current) => !current); /*현재값이 true면 flase, false면 true*/
}
return(
<div>
<h1>Super Converter</h1>
<div>
<label htmlFor="minutes">Minutes</label>
<input
value={flipped ? amount * 60 : amount} /*fliped 여부에 따라 다른 값*/
id="minutes"
placeholder="Minutes"
type="number"
onChange={onChange}
disabled={flipped} /*input 비활성화 여부*/
/>
</div>
<div>
<label htmlFor="hours">Hours</label>
<input
value={flipped ? amount : Math.round(amount / 60)} /*fliped 여부에 따라 다른 값*/
id="hours"
placeholder="Hours"
type="number"
onChange={onChange}
disabled={!flipped} /*input 비활성화 여부*/
/>
</div>
<button onClick={reset}>Reset</button>
<button onClick={onFlip}>{!flipped ? 'Flip': 'Turn back'}</button>
</div>
);
}
ReactDOM.render(<App/>, root);
State의 true/false 여부로 상태 관리가 가능하다!
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function MinutesToHours() {
const [amount, setAmount] = React.useState(0);
const [inverted, setInverted] = React.useState(false);
const onChange = (event) => {
setAmount(() => event.target.value);
};
const onInverted = () => {
setInverted((current) => !current);
return setAmount(() => 0);
};
return (
<div>
<h3>Minutes & Hours</h3>
<div>
<label htmlFor="minutes">Minutes</label>
<input
value={inverted ? amount * 60 : amount}
id="minutes"
placeholder="Minutes"
type="number"
onChange={onChange}
disabled={inverted}
/>
</div>
<div>
<label htmlFor="Hours">Hours</label>
<input
value={inverted ? amount : Math.round(amount / 60)}
id="Hours"
placeholder="Hours"
type="number"
disabled={!inverted}
onChange={onChange}
/>
</div>
<button onClick={() => setAmount(() => 0)}>Reset</button>
<button onClick={onInverted}>
{inverted ? "Turn back" : "Invert"}
</button>
</div>
);
}
function KmToMiles() {
const [amount, setAmount] = React.useState(0);
const [invert, setInvert] = React.useState(false);
const kmChange = (event) => {
setAmount(() => event.target.value);
};
return (
<div>
<h3>KM & Miles</h3>
<div>
<label htmlFor="km">Kilometers</label>
<input
onChange={kmChange}
disabled={invert}
value={invert ? parseFloat(amount * 1.60934).toFixed(4) : amount}
id="km"
placeholder="Kilometers"
type="number"
/>
</div>
<div>
<label htmlFor="miles">Miles</label>
<input
onChange={kmChange}
value={invert ? amount : parseFloat(amount * 0.621371).toFixed(4)}
disabled={!invert}
id="miles"
placeholder="Miles"
type="number"
/>
</div>
<button onClick={() => setAmount(() => 0)}>Reset</button>
<button
onClick={() => {
setInvert((current) => !current);
return setAmount(() => 0);
}}
>
{!invert ? "Invert" : "Turn back"}
</button>
</div>
);
}
function App() {
const [index, setIndex] = React.useState("-1");
const onSelect = (event) => {
return setIndex(() => event.target.value);
};
return (
<div>
<h1>Super Converter</h1>
<select onChange={onSelect}>
<option value="-1">Select</option>
<option value="0">Minutes & Hours</option>
<option value="1">Km & Miles</option>
</select>
<hr />
{index === "0" ? (
<MinutesToHours />
) : index === "1" ? (
<KmToMiles />
) : <h3>Select Option!</h3>}
</div>
);
}
const root = document.getElementById("root");
ReactDOM.render(<App />, root);
</script>
</html>
같은 원리로 state를 활용해 option에 따라 다른 컴포넌트를 렌더링 할 수 있다! (Flip -> Invert)
Props
Props를 통해 부모 컴포넌트에서 자식 컴포넌트로 데이터를 보낼 수 있다
<!DOCTYPE html>
<html>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
function Btn({ buttonName, fontSize = 10 } /*props*/ ) {
return (
<button
style={{
backgroundColor: "teal",
color: "white",
padding: "10px 20px",
border: 0,
borderRadius: "10px",
marginRight: "5px",
fontSize, /*fontSize: props.fontSize*/
}}
>
{buttonName /*props.buttonName*/}
</button>
);
}
Btn.propTypes = {
buttonName: PropTypes.string.isRequired,
fontSize: PropTypes.number,
};
const App = () => {
return (
<div>
<Btn buttonName={"Save Changes"} fontSize={18} />
<Btn buttonName={"Confirm"} />
</div>
);
};
const root = document.getElementById("root");
ReactDOM.render(<App />, root);
</script>
</html>
컴포넌트 커스텀을 통해 효율적인 재사용이 가능하며 PropTypes로 Props의 Type을 제한하기도 한다
본 내용은 노마드코더의 'ReactJS로 영화 웹 서비스 만들기'를 바탕으로 작성되었습니다
'Front-end > React' 카테고리의 다른 글
[TIL] 첫 React 백엔드 연동 (2) | 2021.12.06 |
---|---|
[노마드코더] #3 CRA, Effects (2) | 2021.11.17 |
[노마드코더] #1 Introduction (0) | 2021.11.13 |
[TIL] styled-components 드롭 다운 메뉴 만들기 (4) | 2021.09.18 |
[코딩애플] #6 useContext, Tab UI, Animation (2) | 2021.08.20 |