갑자기 시작하게 된 리액트... 공식 문서 자습서 보고 도전
React로 대화형 틱택토 게임을 만들어 보는 튜토리얼이 올라와 있다. 틱택토 게임은 처음 보는데 약간 둘이 하는 3x3짜리 빙고 느낌? 연속으로 세 칸를 가로, 세로, 대각선 방향으로 먼저 이으면 이기는 게임을 만드는 것 같다. 근데 이제 우리가 만들 건 오른쪽에 진행 상황 기록을 곁들인
사용자 인터페이스를 만들기 위한 JavaScript 라이브러리
공홈에 들어가자마자 떡하니 박혀 있는 설명이다. 리액트 시작하기 전에 자바스크립트 먼저 익히고 오라고 이런 리소스를 소개해준다. 자주 참고하게 될 것 같다
사이트에서 "직접 구현해보면서 학습하는 것을 원하시는 경우, 실용적인 자습서부터 시작"하라고 하길래 개념 가이드 보기 이전에 자습서부터 보기로 결정했다
에디터는 VSCode를 선택했다.
Node.js는 JavaScript로 브라우저 밖에서 서버를 구축하는 등의 코드를 실행할 수 있게 해주는 런타임 환경이다. 설치가 될 때 패키지 매니저 도구인 npm도 같이 설치가 된다. 리액트도 하나의 패키지!
npx create-react-app my-app
cd my-app
npm start
첫째줄에서 npx는 오타가 아니라 npm 5.2+ 버전의 패키지 실행 도구
my-app 이라는 리액트 프로젝트를 생성하고
프로젝트 디렉토리로 이동 후,
실행하면 기본적으로 localhost:3000에서 프로젝트를 볼 수 있다.
자습서에서 프로젝트에 필요한 css 파일과 기본 js 템플릿을 제공하므로, 먼저 src/
폴더의 모든 파일을 삭제한다.
cd my-app
cd src
# Mac 또는 Linux 사용자의 경우
rm -f *
# Windows 사용자
del *
# 다시 프로젝트 폴더로 돌아가세요.
cd ..
삭제가 완료됐으면, src/
폴더에 index.css 파일을 만들고 이 CSS 코드를 복붙한다.
다음으로 src/
폴더에 index.js 파일을 만들고 이 JS 코드를 복붙한다.
그 다음, index.js 파일 상단에
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
를 추가해 주면 리액트 사용 준비 완료
npm start
명령어를 실행하니 브라우저가 열리고, 비어 있는 틱택토 필드를 확인할 수 있다.
class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}
// 사용 예제: <ShoppingList name="Mark" />
컴포넌트는 개념적으로 props를 input으로 하고 UI가 어떻게 보여야 하는지 정의하는 React Element를 output으로 하는 함수입니다. 따라서 합성을 이용하여 "UI를 재사용할 수 있고 독립적인 단위로 쪼개어 생각"할 수 있게 합니다. 출처
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Square extends React.Component {
render() {
return (
<button className="square">
{/* TODO */}
</button>
);
}
}
class Board extends React.Component {
renderSquare(i) {
return <Square />;
}
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
class Game extends React.Component {
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{/* status */}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
}
// ========================================
ReactDOM.render(
<Game />,
document.getElementById('root')
);
코드를 살펴보면 세 가지 React 컴포넌트를 확인할 수 있다.
<button>
을 렌더링Board 컴포넌트에서 Square 컴포넌트로 데이터를 전달해 보자.
Square에 value
prop을 전달하기 위해 renderSquare
함수 수정
class Board extends React.Component {
renderSquare(i) {
return <Square value={i} />;
}
}
값을 표시하기 위해 Square
의 render
함수 수정
class Square extends React.Component {
render() {
return (
<button className="square">
{this.props.value}
</button>
);
}
}
아래와 같이 버튼 내에 전달받은 i가 표시되는 것을 확인할 수 있다.
Square 컴포넌트를 클릭하면 "X"가 체크되도록 만들어보자.
Square
의 render
함수 수정
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => alert('click')}>
{this.props.value}
</button>
);
}
}
화살표 함수는 나중에 다룰 것... 클릭했을 때 alert를 띄우는 것까지 수정했다.
다음 단계로 Square
컴포넌트를 클릭한 것을 "기억하게" 만들어 "X" 표시를 채워 넣으려고 한다. 무언가를 "기억하기" 위해 컴포넌트는 state를 사용한다.
React 컴포넌트는 생성자에 this.state
를 설정하는 것으로 state를 가질 수 있다. this.state
는 정의된 컴포넌트에 대해 비공개로 간주해야 한다.
class Square extends React.Component {
constructor(props) { //생성자 추가
super(props);
//모든 React 컴포넌트 클래스는 생성자를 가질 때
//super(props) 호출 구문부터 작성해야 한다.
this.state = {
value: null, //state 초기화
};
}
render() {
return (
<button
className="square"
onClick={() => this.setState({value: 'X'})}
>
{this.state.value}
</button>
);
}
}
Square
의 render
함수 내부에서 onClick 핸들러
를 통해 this.setState
를 호출하는 것으로 React에게 <button>
을 클릭할 때 Square
가 다시 렌더링해야 한다고 알릴 수 있다. 업데이트 이후에 Square
의 this.state.value
는 'X'가 되어 게임 판에서 X가 나타나는 것을 확인할 수 있다.