React 스터디 3일차

오늘의 키워드
1. React.useState()
2. Array Destructuring(배열 구조 분해 할당)
3. 상태 끌어올리기(Lifting up state)

오늘의 예제코드

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>react day3</title>
	<style>
		.content-wrap {
			text-align: center;
			margin-top: 250px;
		}

		.count-btn button {
			margin: 0 5px;
			font-size: 18px;
			padding: 5px 10px;
			border: none;
			border-radius: 3px;
			transition: all .13s;
		}

		.count-btn button:hover {
			cursor: pointer;
			color: #fff;
			background: #61dbfb;
		}
	</style>
</head>

<body>
	<div id="root"></div>

	<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
	<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
	<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
	<script type="text/babel">
			
		// 카운트 될 숫자 컴포넌트   
		const Count = (props) => <h1>{props.children}</h1>;
        
		// 카운팅 이벤트 버튼
		const Buttons = ({ countDown, countUp, resetCount }) => (
			<div className="count-btn">
				<button type="button" onClick={countDown}>-</button>
				<button type="button" onClick={countUp}>+</button>
				<button type="button" className="reset-btn" onClick={resetCount}>reset</button>
			</div>
		);

		// 요소 컴포넌트들을 하나의 컴포넌트로 정의 (부모 컴포넌트)
		const App = () => {
			// count 상태값 정의 및 초기화
			const [count, setCount] = React.useState(0);

			// 카운트 다운 함수
			function handleCountDownClick() {
				console.log('count down');
				setCount(count - 1);
			}

			// 카운트 업 함수
			function handleCountUpClick() {
				console.log('count up');
				setCount(count + 1);
			}

			// 카운트 리셋 함수
			function handleResetCountClick() {
				console.log('reset count');
				setCount(0);
			}

			return (
				<div className="content-wrap">
					<Count>{count}</Count>
					<Buttons
						countDown={handleCountDownClick}
						countUp={handleCountUpClick}
						resetCount={handleResetCountClick} />
				</div>
			);
		}
	
    	// 렌더링 할 최상위 부모 컴포넌트
		const root = document.querySelector('#root');

		// 렌더링 함수 호출
		ReactDOM.render(<App />, root);

	</script>
</body>

</html>

예제 소개
버튼을 클릭하여 숫자 카운트가 증가, 감소 하는 간단한 예제이다.
또 리셋 버튼을 클릭하면 다시 초기값 (0)으로 초기화 된다.
지난 시간에는 이벤트가 일어날 해당 컴포넌트에 이벤트 함수를 정의하여 사용했으나, 이번 시간에는 부모 컴포넌트에 이벤트를 정의하고 해당 이벤트로 인해 변화 된 상태 값(count)을 다른 자식에게도 props 데이터를 넘겨 줄 것이다.
상태 값, 또는 이벤트를 부모 컴포넌트로 끌어 올려 사용하는 것을 "상태 끌어올리기" 라고 칭한다. 그리고 React.userState() 를 사용하여 상태값을 정의 및 초기화를 하고 활용해볼 것이다.

우선 이번 예제에서 필요한 요소들을 고민해보자.

  1. 카운트 될 숫자
  2. 카운팅 이벤트 버튼(증가, 감소, 초기화)

이 필요한 요소들을 각각의 컴포넌트로 정의하고

// 카운트 될 숫자 컴포넌트   
const Count = (props) => <h1>{props.children}</h1>;

// 카운팅 이벤트 버튼
const Buttons = ({ countDown, countUp, resetCount }) => (
	<div className="count-btn">
    	<button type="button" onClick={countDown}>-</button>
        <button type="button" onClick={countUp}>+</button>
        <button type="button" className="reset-btn" onClick={resetCount}>reset</button>
	</div>
);

이전 시간(2일차)에서 props, 객체 구조 분해 할당, onClick에 대해 언급 하였기에 그 부분에 대해서는 skip

정의한 요소 컴포넌트들을 하나의 컴포넌트로 정의한다.
지난 시간까지는 정의한 컴포넌트들을 변수로 담아 렌더링 하였지만 오늘부터는 그 자식 컴포넌트를 품는 부모 컴포넌트로 선언해서 컴포넌트 태그로 사용하겠다.

우리가 지금까지 컴포넌트를 선언한 방식과 동일하다.

// 요소 컴포넌트들을 하나의 컴포넌트로 정의 (부모 컴포넌트)
const App = () => {
	// 카운트 될 숫자의 상태 값
	const [count, setCount] = React.useState(0);

	// 카운트 다운 함수
    function handleCountDownClick() {
    	console.log('count down');
        setCount(count - 1);
	}

	// 카운트 업 함수
	function handleCountUpClick() {
		console.log('count up');
		setCount(count + 1);
	}

	// 카운트 리셋 함수
	function handleResetCountClick() {
		console.log('reset count');
		setCount(0);
	}

	return (
		<div className="content-wrap">
			<Count>{count}</Count>
			<Buttons
				countDown={handleCountDownClick}
				countUp={handleCountUpClick}
				resetCount={handleResetCountClick} />
		</div>
	);
}

요소들을 담아 return 하는 것 이외에도 여러 내용들이 담겨 있는데,
하나씩 살펴보자.

우선 오늘 예제의 핵심 키워드인 React.useState()에 대해 설명하겠다.

State(상태)란?
State는 동적인 값(상태)를 의미한다.
props처럼 부모 컴포넌트에서 자식 컴포넌트로 영향을 주는 데이터이지만,
props는 함수의 인자로 자식 컴포넌트에 전달되는 반면, state는 (함수 내에 선언된 변수처럼) 컴포넌트 안에서 관리된다는 차이가 있다.

React.useState()는 동적으로 상태를 관리할 수 있는 메소드이다.

  • 문법
    React.useState(상태 초기값);
    소괄호() 안에는 상태 초기의 값을 지정해주는 것이다.

카운트 될 숫자의 state를 변수로 선언해준다.

const countState = React.useState(0);

선언한 countState를 콘솔에 출력해보면

이와 같이 배열의 형태로 출력되는 것을 확인할 수 있다.
useState() 메소드는 결과로 배열을 return 하는 것이다.

그 배열의 데이터를 살펴보면
배열의 첫번째 값은 방금전 React.useState(0)로 괄호안에 초기 지정해준 값이 출력된다.
배열의 두번째 값은 함수가 담겨 있는 것이 확인되는데 저 함수는 바로 초기로 지정해준 상태 값(배열의 첫번째 요소값)을 변경해주는 함수이다.

예제를 통해 useState()에 대해 알아보자.
countState 배열의 첫번째, 두번째 값을 각각 사용하기 위해 따로 변수선언을 한다.

// 카운트 상태값 (배열의 첫번째 요소)
const count = countState[0];

// 카운트 상태값을 변경해 줄 함수 (배열의 두번째 요소)
const setCount = countState[1];

이렇게 해주면 조금 더 배열의 값을 변수로 편히 사용할 수 있게 된다.

지난 시간에 배웠던 객체 구조분해할당(destructuring)이 기억이 날지 모르겠다.
배열도 마찬가지로 구조분해할당이 가능하다.

방금 선언했던 countState(state 선언), count(상태 값), setCount(상태값 변경 함수)를
한번의 선언으로 모두 가능하게 만들어 보겠다.

const [count, setCount] = React.useState(0);

끝.

이것이 배열 구조분해할당이다.

  • 문법
    const [배열 데이터의 변수명 지정, 배열 데이터의 변수명 지정] = 해당 배열(배열 데이터의 출처)

이처럼 선언해주면 count, setCount를 개별적인 변수 선언 없이도 사용가능하다.

또 App 컴포넌트 내부의 이벤트 함수들을 보면

const App = () => {
	...

	// 카운트 다운 함수
    function handleCountDownClick() {
    	console.log('count down');
        setCount(count - 1);
	}

	// 카운트 업 함수
	function handleCountUpClick() {
		console.log('count up');
		setCount(count + 1);
	}

	// 카운트 리셋 함수
	function handleResetCountClick() {
		console.log('reset count');
		setCount(0);
	}

	...
}

선언했던 setCount() 함수를 사용하여 count 상태 값을 변경하는 것을 확인할 수 있다.
선언한 이벤트 함수를 버튼에 심어주어야 하는데 부모 컴포넌트에 선언했기 때문에 자식 컴포넌트 Buttons에 props로 전달해 주어야 한다.

const App = () => {
	...

	return (
		<div className="content-wrap">
			<Count>{count}</Count>
			<Buttons
				countDown={handleCountDownClick}
				countUp={handleCountUpClick}
				resetCount={handleResetCountClick} />
		</div>
	);
}

Buttons 컴포넌트에 countDown, countUp, resetCount라는 이름으로 이벤트를 전달해 주었다.

이벤트를 자식 컴포넌트로 내려주게 되면 Buttons 컴포넌트 선언 함수에서

// 카운팅 이벤트 버튼
const Buttons = ({ countDown, countUp, resetCount }) => (
	<div className="count-btn">
    	<button type="button" onClick={countDown}>-</button>
        <button type="button" onClick={countUp}>+</button>
        <button type="button" className="reset-btn" onClick={resetCount}>reset</button>
	</div>
);

객체 구조분해할당 방식으로 이벤트를 받아 각 버튼에 onClick 속성을 지정해주었다.

최종적으로 어김없이 ReactDOM.render() 함수로 렌더링한다.

/ 렌더링 할 최상위 부모 컴포넌트
const root = document.querySelector('#root');

// 렌더링 함수 호출
ReactDOM.render(<App />, root);

(!) 오늘은 변수가 아닌 부모 컴포넌트로 정의하였기 때문에 렌더링 함수 첫번째 인자로
변수명이 아닌 태그로 작성한다.

저장하고 브라우저에서 확인해보자.

우선 증가버튼을 클릭하면


증가하고,
감소버튼을 클릭하면


감소한다.

증가, 감소를 반복하며 가지고 놀다 reset 버튼을 클릭하면



초기화가 되는 것을 확인할 수 있다.

이렇게 해서 오늘의 예제는 끝.

좋은 웹페이지 즐겨찾기