ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] React Docs해석하면서 공부하기 2장 Tic-Tac-Toe
    React 2023. 3. 8. 01:52

    개요

    React Docs의 Tic-Tac-Toe를 만들어보면서 React에 대한 내용을 공부하며 스스로 정리해보자.

     

     

    1.  초기 코드

    필요한 파일은 App.js, index.js, styles.css과 pulic폴더가 필요하다.

     

    참고 : https://codesandbox.io/embed/cold-dream-wjwuw8?fontsize=14&hidenavigation=1&module=/App.js&editorsize=70&view=split 

     

    cold-dream-wjwuw8 - CodeSandbox

    cold-dream-wjwuw8 using react, react-dom, react-scripts

    codesandbox.io

     

    App.js 에서는 컴포넌트를 생성합니다.

    React의 컴포넌트는 사용자 인터페이스의 일부를 표시하는 재사용이 가능한 코드조각입니다.

     

     

     

    우선 Square함수를 정의하고 X가 표시된 버튼을 만들어 봅시다.

    export default function Square() {
      return <button className="square">X</button>;
    }

     

    export키워드를 사용한다면 파일 외부에서 이 함수에 접근이 가능합니다.
    default키워드를 사용한다면 다른파일에서 이 함수가 주요한 함수임을 알려줍니다.
    return 뒤의 코드는 함수호출자에게 값으로 반환됩니다.
    <button>은 JSX Element입니다. JavaScript코드와 HTML태그의 조합으로 표시할 내용을 설명합니다.
    className="square"은 버튼의 prop또는 프로퍼티입니다. CSS에 스타일을 지정하는 방법을 알려줍니다.

     

    index.js는 App.js에서 만든 컴포넌트와 웹 브라우저사이의 다리역할을 합니다.

     

     

     

     

    보드 만들기

    이제 본격적으로 tic-tac-toe를 만들어봅시다.

    App.js에서 x버튼을 하나 만들어 보았습니다.

    하지만 우리는 총 9개의 버튼이 필요합니다. 제일 단순한 방법으로 복붙으로 해결해 봅시다!

    export default function Square() {
      return <button className="square">X</button><button className="square">X</button>;
    }

     

    이렇게 코드를 작성한다면  우리는 오류를 만나게 될 것입니다.

    /src/App.js: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?

     

    이유는 React컴포넌트는 항상 단일 JSX엘리먼트를 반환해줘야 합니다.

    이 문제를 해결하기 위해서는 fragments를 사용하여 JSX를 래핑해준다면 해결할 수 있습니다.

    (참고: https://beta.reactjs.org/reference/react/Fragment)

     

     

     

    자 이제 x가 두개인 버튼이 생성됩니다.

    귀엽다

    자 이제 9개의 버튼을 복붙한다면 일렬로 된 x가 나타납니다.

    우리는 한줄로된 버튼이 필요한 것이 아닌 3x3형태가 필요합니다.

    해결하기 위해서 우린 CSS클래스를 추가하여 해결해봅시다.

     

    export default function Square() {
      return (
        <>
          <div className="board-row">
            <button className="square">1</button>
            <button className="square">2</button>
            <button className="square">3</button>
          </div>
          <div className="board-row">
            <button className="square">4</button>
            <button className="square">5</button>
            <button className="square">6</button>
          </div>
          <div className="board-row">
            <button className="square">7</button>
            <button className="square">8</button>
            <button className="square">9</button>
          </div>
        </>
      );
    }

    결과물

     

    위와 같이 코드를 작성했다면 좋은 결과물을 보여지게 됩니다.

    이 함수는 더이상 사각형(square)를 뜻하지 않기에 함수명도 Board로 변경해줍시다!

     

     

     

     

     

    Props로 데이터를 전달하기

    이제 값이 비어있는 상태에서 x로 변경하는 것을 구현하고 싶습니다.

    하지만 하나하나 복붙하는 행위말고 좀 더 스마트한 방법을 구상해봅시다!

    React의 컴포넌트 아키텍처를 사용한다면 재사용한 컴포넌트를 만들어 중복된 코드를 해결할 수 있습니다.

     

    우선 우리가 만든 Board컴포넌트에서 첫 번째 사각형을 정의하는 코드를 새롭게 Square라는 함수를 만들어봅시다.

    function Square() {
      return <button className="square">1</button>;
    }
    
    export default function Board() {
      // ...
    }

     

    이후 Board컴포넌트를 JSX 문법을 사용하여 Square컴포넌트를 렌더링하게 만들어볼까요?

    // ...
    export default function Board() {
      return (
        <>
          <div className="board-row">
            <Square />
            <Square />
            <Square />
          </div>
          <div className="board-row">
            <Square />
            <Square />
            <Square />
          </div>
          <div className="board-row">
            <Square />
            <Square />
            <Square />
          </div>
        </>
      );
    }

     

    여기서 포인트는 컴포넌트명은 항상 대문자로 시작해야합니다!

     

    자 우리의 결과물은 1이 9개가 만들어진 버튼이 나올 것입니다.

     

    다음 단계는 1이 아닌 우리가 원하는 값이 나오길 바랍니다.

    function Square()에 value를 전달해 봅시다.

    function Square({ value }) {
      return <button className="square">1</button>;
    }

    function  Square({value}) 는 사각형 컴포넌트에 value라는 prop을 전달이 가능합니다.

    이제 1 대신 원하는 value값을 표시해야합니다.

    여기서 중요한 점은 바로 "이스케이프문"인 {}을 활용하는 것입니다.

    JSX에서는 JavaScript로 이스케이프하기 위해서는 중괄호를 사용합니다.

     

    function Square({value}) {
    	return <button className="square">{value}</button>
    }

    위 코드를 적용한다면 빈 보드가 보일 것입니다.

    그 이유는 Square컴포넌트에 아직 value prop을 전달하지 않았기 때문입니다.

    Square컴포넌트에 value prop을 추가해봅시다.

     

    export default function Board() {
      return (
        <>
          <div className="board-row">
            <Square value="1" />
            <Square value="2" />
            <Square value="3" />
          </div>
          <div className="board-row">
            <Square value="4" />
            <Square value="5" />
            <Square value="6" />
          </div>
          <div className="board-row">
            <Square value="7" />
            <Square value="8" />
            <Square value="9" />
          </div>
        </>
      );
    }

     

    이제 숫자가 나타난 보드가 나타납니다.

     

    최종코드 

    https://codesandbox.io/embed/keen-ellis-w6zwff?fontsize=14&hidenavigation=1&theme=dark&module=/App.js&editorsize=70&view=split

     

     

     

    상호작용하는 컴포넌트 작성하기

    이제부터는 컴포넌트를 클릭한다면 X로 채워지는 방법을 만들어보겠습니다.

    Square내부에 handleClick이라는 함수를 선언후 JSX의 props에 onClick을 추가해줍니다.

     

    function Square({ value }) {
      function handleClick() {
        console.log('clicked!');
      }
    
      return (
        <button
          className="square"
          onClick={handleClick}
        >
          {value}
        </button>
      );
    }

    이제 사각형을 클릭한다면 Console에 "clicked!"가 표시됩니다.

     

     

     

    useState

    컴포넌트가 클릭된 것을 기억하기 위해서는 state를 사용합니다.

    React는 컴포넌트에서 무엇을 호출하여 "기억"할 수 있는 useState라는 함수를 제공합니다.

    이제 컴포넌트에서 value prop을 제거하고 useState를 사용해 봅시다.

     

    import {useState} from 'react';
    
    function Square() {
    	const [value, setValue] = useState(null);
        
        function handleClick() {~~~}
    }

    useState코드 줄을 해석해보면 value는 값을 저장하고 setValue는 값을 변경하는데 사용되는 함수 입니다.

    useState에 전달된 null은 상태변수의 초기값으로 사용이 되며 value는 null입니다.

     

    Square컴포넌트의 value prop도 제거하고 Square가 클릭되었을 때 "X"를 표시하도록 변경을 해봅시다.

     

    function Square() {
      const [value, setValue] = useState(null);
    
      function handleClick() {
        setValue('X');
      }
    
      return (
        <button
          className="square"
          onClick={handleClick}
        >
          {value}
        </button>
      );
    }
    
    export default function Board() {
      return (
        <>
          <div className="board-row">
            <Square />
            <Square />
            <Square />
          </div>
          <div className="board-row">
            <Square />
            <Square />
            <Square />
          </div>
          <div className="board-row">
            <Square />
            <Square />
            <Square />
          </div>
        </>
      );
    }

    onClick핸들러에서 set함수를 호출한다. 이제 <button>이 클릭될때마다 Square가 재렌더링인됩니다.

    Square의 value인 값은 "X"이므로 클릭을 한다면 X가 보여질 것입니다.

     

     

     

     

    정리

     

    이번 챕터에서는 각 파일에 대해서 분석하며 알아보았고 컴포넌트의 개념, props에 대한 공부, useState를 활용하여 상호작용되는 컴포넌트를 만들어 보았습니다.

    다음 챕터에서는 tic-tac-toe을 활용하여 state를 끌어올려 해결하는 방법, 불변성 등에 대한 공부를 해보겠습니다.

     

    참고 :  https://beta.reactjs.org/learn/tutorial-tic-tac-toe

    댓글

Designed by Tistory.