[React] 웹 게임 - ❶ 구구단

지수토리·2021년 7월 9일
2

React

목록 보기
1/2
post-thumbnail

리액트 무료 강좌 (웹게임) - ZeroCho TV
-> React 기본 사용법을 가르쳐 주는 무료 강좌를 학습한 내용을 바탕으로 정리해보았습니다.

1. React 사용 이유

React : 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리
📌 리액트 공식문서 참조

  • 리액트를 쓰는 이유?
    -> 사용자 interface를 편하게 만들기 위해
    -> 데이터를 화면에 반영할 때 데이터와 화면 일치 시키기 좋음. 데이터 처리 👍
    -> 중복되는 요소를 하나로 묶어줄 수 있어 유지보수가 좋음.

2. 첫 리액트 Component

index.html 파일을 만들어 react와 react-dom script를 불러옵니다.

<html>
    <head>
        <meta charset="UTF-8"/>
        <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>
        <!-- .js 앞에 development는 개발용을 뜻하고, 나중에 배포할 때는 production으로 바꿔야 한다 -->
    </head>
    <body>
        <div id="root"></div>  <!--component를 rendering 할 root -->
        <script>
            const e = React.createElement; // createElement-> html 태그를 만들어주는 함수
            class LikeButton extends React.Component { // class 바로 component 하나. 
                constructor(props){ // constructor는 component가 실행될 때 가장 먼저 실행되는 부분
                    super(props); 
                }
                render(){
                    return e('button', null, 'Like'); // e는 태그를 만들어주는 함수 <button> Like </button> 이런테그 만들어짐
                }
            }
        </script>
        <script>// react가 위 script에서 'component를 이렇게 만들겠다' 라고 하는 것을 ReactDom이 웹에 실제로 구현, 렌더링 하는 것임. 
            ReactDOM.render(e(LikeButton), document.querySelector('#root'));
        </script>

    </body>
</html> <!-- 실행결과 : <div id="root"><button>Like</button> </div>-->

3. HTML 속성과 상태(state)

HTML 속성

수정 전

<script>
    render(){
	return e('button', null, 'Like'); 
    }
</script>

-> 이 때 null은 HTML 속성을 넣는 자리로, 객체 형식으로 표현합니다.

수정후

<script>
    render(){
	return e('button', {onClick: () => {console.log('clicked')}, type: 'submit'}, 'Like'); 
        // 태그를 만들어주는 함수 => <button type = "submit">Like</button>
        // 참고로 html 속성을 javascript로 표현할 때는 onClick에서 C를 대문자로 표현해야 합니다.
    }
</script>

Chrome 개발자 도구를 열어 Console을 확인해보면 Like 버튼을 클릭할 때마다 cliked 숫자가 증가 되는 것을 확인 할 수 있습니다.

상태 (state) = 바뀔 여지가 있는 부분

ex) Like 버튼은 '버튼을 누르기 전', '누른 후' 이렇게 상태가 바뀔 여지가 있습니다.

       ...
       <script>
           const e = React.createElement; 
           class LikeButton extends React.Component { 
               constructor(props){ 
                   super(props); 
                   this.state={
                       liked : false,
                   }; // 상태를 넣어준다.
               }
               render (){
                   return e('button', {onClick: () => {this.setState({liked: true})}, type: 'submit'}, 'Like'); 
                   //클릭을 했을 때 상태를 true로 바꿔준다. 
               }
           }
       </script>
       ...

이때 state를 확인하는 방법은 React Developer Tools 확장 프로그램을 설치하여 개발자도구에서 Components 확인하는 것 입니다.

✔️ 확장 프로그램 설치

✔️ chrome://extensions/ 에서 세부정보 클릭하여 '파일 URL에 대한 액세스 허용' 하기

✔️ 다시 개발자 도구를 열어 Component를 확인해보면 클릭 전에는 state가 false 클릭 후에는 state가 true로 바뀌는 것을 확인 할 수 있습니다.

⭐️ 그럼 화면에 반영하려면 어떻게 해야할까?
render() 안에서 반영을 하면 됩니다.
클릭 전에는 Button 이름이 like, 클릭 후에는 Button이름이 liked가 되도록 변경합니다.

<script>
...
render (){
      return e('button', 
      {onClick: () => {this.setState({liked: true})}, type: 'submit'}, 
      this.state.liked === true ? 'Liked' : 'Like', // 여기가 가장 중요한 부분 !! jquery는 직접 바꿔줘야 하지만 React를 사용하면 상태에 따라서 값을 자동으로 바꿀 수 있음 => 데이터와 화면을 react가 일치시켜준다.
      );  // 상태에 따라서 화면이 자동으로 바뀜
}
</script>
...

4. JSX와 babel

위의 코드가 다소 복잡하여 "태그"를 사용하여 이를 조금 더 개선을 해보면 ,,

...
<head>
	...
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<script type ="text/babel"> // script type 추가
...
render (){
    return <button type= "submit"
    onClick= {() => { this.setState({ liked :true })}}>
    {this.state.liked === true ? 'Liked': 'like'} 
    </button>; //javascript에서 html 태그를 쓰는 이 문법을 지원 안하기 때문에 "babel"을 써야 함.
    // 이걸 JSX = Javascript + XML 라고 한다. 
}
</script>
<script type ="text/babel"> // script type 추가
     ReactDOM.render(<div><LikeButton /><LikeButton /><LikeButton /><LikeButton /></div>, document.querySelector('#root')); 
     // --> 코드를 훨씬 간추릴 수 있어 재사용성 너무 좋다.
</script>

JSX = Javascript + XML
javascript에서 html 태그를 쓰는 문법을 지원 안하기 때문에 "babel"을 써야합니다.
babel을 불러오는 script를 head 에 추가해주고, 그 아래의 script type을 " text/babel "로 바꾸어 줍니다.

5. 첫 번째 Q&A

✋ < button > 과 < LikeButton /> 차이?
-> 테그 안에 대문자로 시작하는 것(LikeButton)은 react component 이다.
✋ 바벨은 어떻게 적용이 되는가?
-> 바벨은 최신 js 문법을 모든 브라우저에서 사용할 수 있도록 변환해주는 자바스크립트 컴파일러로, jsx를 다 createElement로 바꾸어 준다. 세부설정은 webpack이나 바벨 툴로 설정해주어야 한다.

6+7. 구구단 리액트로 만들기 + Class 매서드

  • 바뀌는 것(state) : 첫번째 숫자, 두번째 숫자, 입력값 ,결과값
<html>
    <head>
        <meta charset="UTF-8"/>
        <title> 구구단 </title>
        <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/babel.min.js"></script>
    </head>
    <body> <!--바뀌는 것들은 state로 등록하자 !!!-->
        <div id="root"></div> 
        <script type ="text/babel">
            class GuGuDan extends React.Component { // gugudan이라는 component를 만들고 그것을 화면에 그리겠다. 
                constructor(props){
                    super(props); 
                    this.state = { 
                        first: Math.ceil(Math.random()* 9),
                        second: Math.ceil(Math.random()* 9),
                        value: '', 
                        result: '', 
                    };
                }
                onSubmit = (e) =>{
                                e.preventDefault();
                                if (parseInt(this.state.value) === this.state.first * this.state.second) {
                                    this.setState({
                                        return {
                                        result: '정답: '+ prevState.value, 
                                        first: Math.ceil(Math.random()* 9), // 정답이면 새로운 숫자 나타나기.
                                        second: Math.ceil(Math.random()* 9),
                                        value: '',
                                    });
                                }else{
                                    this.setState({
                                        result: '땡', // 숫자는 그대로 냄기기
                                        value: '',
                                    });
                                }          
                 };
                onChange = (e)=> { // 함수로 빼낼 수 있다. 이때는 function을 쓸 수 없다. this가 달라지기 때문에 
                    this.setState({ value: e.target.value})
                };
                
                render(){ // div안의 {}에는 javascript를 쓸 수 있다.
                    return (
                        <div> 
                            <div> {this.state.first} 곱하기 {this.state.second}? </div>
                            <form onSubmit = {this.onSubmit}> // 웬만하면 javascript랑 jsx랑 섞어쓰지 말고, {}안 내용을 class의 매서드로 만들어 줌으로써 깔끔하게!
                                <input type ="number" value= {this.state.value} onChange={this.onChange}/> 
                                {/* -> 참고로 이것은 JSX 주석임. XML이라 input 닫는 테그 안붙이면 에러 발생 주의 !!*/}
                                <button>입력!</button>
                            </form> 
                            <div>{this.state.result}</div>
                        <div/>
                    );
                }
            }
        </script>
        
        <script type ="text/babel">
            ReactDOM.render(<div><GuGuDan /><hr/><GuGuDan /><hr/><GuGuDan /></div>, document.querySelector('#root'));
        </script>
        
    </body>
</html>

8. Fragment와 기타 팁들

✔️ <React.Fragment>
React 의 모든 컴포넌트는

태그로 감싸야 하는 규칙이 있는데, 이는 css 적용 등에서 번거롭기 때문에 <React.Fragment>로 대체하여 제거할 수 있습니다.

...
<script type ="text/babel">
    render(){ 
             console.log('렌덩링');
             return (
              <React.Fragment> 
                    <div> {this.state.first} 곱하기 {this.state.second}? </div>
                    <form onSubmit = {this.onSubmit}>
                    	<input ref={this.onRefInput}type ="number" value= {this.state.value} onChange={this.onChange}/> 
                    	<button>입력!</button>
                    </form> 
                    <div>{this.state.result}</div>
               <React.Fragment/>
              );
     }
</script>
...

✔️ 직접 만든 함수는 화살표 함수로 작성 , render는 화살표 함수로 쓸 필요 없다.
onSubmit = function(e) {} ❌
onSubmit = (e) => {} ⭕️

✔️ constructor(){} 없애도 상관 없음!!

  ...
  <script type="text/babel"> // state앞에 this를 빼고 작성
    ...
	state = { 
                        first: Math.ceil(Math.random()* 9),
                        second: Math.ceil(Math.random()* 9),
                        value: '', 
                        result: '', 
                };
    ...
  </script>
  ...

9. 함수형 setState

setState에 바꾸고 싶은 상태를 입력하면 되는데,this.state.value는 현재 state이고, result, first, second, value는 미래 state 이기에 구별을 하고자 합니다.
-> setState안에 새로운 state를 return하는 함수 넣기!!
-> 쉽게 기억하는 방법은 setState안에 this.state가 있으면 return 하는 함수를 작성합시다.

  ...
  <script type ="text/babel">
  ...
          this.setState( (prevState) => {
                return {
                               result: '정답: '+ prevState.value, 
                               first: Math.ceil(Math.random()* 9),
                               second: Math.ceil(Math.random()* 9),
                               value: '',
                         };
          });
  ...
  </script>
  ...

10. ref

input에 focus를 하고 싶을 때는 ref를 사용합니다.

  ...
  <script type ="text/babel">
  ...
  onSubmit = (e) => {
                e.preventDefault();
                if (parseInt(this.state.value) === this.state.first * this.state.second) {
                    this.setState((prevState) => {
                        return {
                            result: '정답: ' + prevState.value,
                            first: Math.ceil(Math.random() * 9), 
                            second: Math.ceil(Math.random() * 9),
                            value: '',
                        };
                    });
                    this.input.focus(); // 커서 깜빡이게
  		  } else {
                    this.setState({
                        result: '땡', 
                        value: '',
                    });
                    this.input.focus(); // 커서 깜빡이게 
                }
            };
  ...
  input;
  onRefInput = (c) => {
                this.input = c;
            };
  render() {        
                console.log('렌덩링');
                return (
                    <>
                        <div> {this.state.first} 곱하기 {this.state.second}? </div>
                        <form onSubmit={this.onSubmit}> {/* ref 추가하기 */}
                            <input ref={this.onRefInput} type="number" value={this.state.value} onChange={this.onChange} />
                            <button id="button" className="button">입력!</button>
                          {/* 주의 !!! label 속성 중에 class-> className으로 for-> htmlFor로 사용해야 함 !!*/}
                        </form>
                        <div>{this.state.result}</div>
                    </>
                );
            }
    }
  </script>
  ...

setState가 실행될 때마다 render()가 실행이 되는데 실행이 너무 많이 되면 실행 시간 오래 걸릴 수도 있으므로 주의해야 합니다.
그리고 render()가 실행될 때마다 함수를 생성하는 일이 없도록 메서드를 따로 선언하는 것이 좋습니다.
ex) input ref={this.onRefInput} value={this.state.value} onChange={this.onChange}

0개의 댓글