FE/React

[React] 틱택토 추가 기능 구현하기 (1)

Juliie 2021. 7. 29. 12:42
잠깐!✋ 이 포스팅은 React 자습서를 따라해보고 복습을 목적으로 하는 포스팅입니다
틀린 부분이 있으면 정정 부탁드립니다!
리액트 자습서(틱택토 만들기) 링크: https://reactjs.org/tutorial/tutorial.html
 

Tutorial: Intro to React – React

A JavaScript library for building user interfaces

reactjs.org

 

리액트 자습서 마지막 부분을 보면 연습을 위해서 추가 기능을 제시해 놓았다

 

1. Display the location for each move in the format (col, row) in the move history list.

(이동 기록 목록에서 특정 형식(, )으로 이동의 위치를 표시해주세요.)

class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      history: [
        {
          squares: Array(9).fill(null),
          lastIndex: -1, /*추가된 변수*/
        },
        ...(생략)

1) 가장 최근에 선택한 인덱스를 나타내는 lastIndex 변수를 정의하고 초기화했다

 

handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();
    const lastIndex = i; /*추가된 부분*/
    squares[i] = this.state.xIsNext ? "X" : "O";
    
    if (calculateWinner(squares) || squares[i]) return;

    this.setState({
      history: history.concat([
        {
          squares: squares,
          lastIndex: lastIndex,  /*추가된 부분*/
        },
      ]),
     ...(생략)

2) 버튼을 클릭하면 실행되는 handleClick()은 setState로 눌린 번호를 lastIndex를 갱신한다

 

render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);

    const moves = history.map((step, move) => {
      const desc = move
        ? "Go to move #" +
          move +
          " (" +
          parseInt(step.lastIndex / 3) +
          "," +
          (step.lastIndex % 3) +
          ")"
        : "Go to game start";
      ...(생략)

3) 마지막으로 Game의 render()에서 lastIndex의 값으로 배열의 좌표값을 구한뒤 출력한다


2. 이동 목록에서 현재 선택된 아이템을 굵게 표시해주세요.

(Bold the currently selected item in the move list.)

//Game 컴포넌트의 render 함수

<li key={move}>
	<button className="moves-button" onClick={() => this.jumpTo(move)}>
    	{desc}
    </button>
</li>
...(생략)
/*index.css*/
.moves-button:focus {
  font-weight: bold;
  border: 3px solid indianred;
}

처음엔 단순하게 focus된 button을 하이라이팅 해주면 되는거 아닌가했는데...

Board의 사각형들도 button으로 구현했어서 사각형도 같이 색칠되는 문제가 있었다🥲

그래서 이동 목록의 버튼들만 className을 지정해서 style을 따로 적용해줬다


3. 사각형들을 만들 하드코딩 대신에 개의 반복문을 사용하도록 Board 다시 작성해주세요.

(Rewrite Board to use two loops to make the squares instead of hardcoding them.)

 

사실 하드코딩 말만 많이 들어봤지 정확한 뜻은 몰랐는데 이번 기회에 알게됐다

*하드코딩: 데이터를 코드 내부에 직접 입력하는 것

//Board 컴포넌트
renderBoard() {
    let rowArr = [];
    for (let i = 0; i < 7; i += 3) {
      let squareArr = [];
      for (let j = 0; j < 3; j++) {
        squareArr.push(this.renderSquare(i + j));
      }
      rowArr.push(<div className="board-row">{squareArr}</div>);
    }
    return rowArr;
  }

 

단순히 기능을 구현하는데 급급했더니 다른 방향의 하드코딩이 된 것 같은 느낌...😅

확실히 상수를 많이 쓰면 유지보수가 힘들어지는 것 같다

기능 구현 전부 끝나면 매개변수로 받아서 for문 돌려야겠다ㅜㅡㅜ

map 써서 컴포넌트 생성하는 방법도 있다는데 그것도 시도해봐야지


나머지 기능은 2편에서...!٩(ˊᗜˋ*)و 


반성

1. 지금은 틱택토가 3x3이라서 좌표값을 구할때 상수 3으로 나눴는데 만약 틱택토 판의 크기가 동적이라면?

➡️ 좌표값을 만드는 함수를 따로 구현해서 호출하자

2. const에 대해서 이해가 부족한듯...🤔따로 정리해서 포스팅 해야겠다

3. 여러개의 컴포넌트를 효율적으로 생성하는 방법? - map, 반복문

1 2 3 4 5 6 7 8