React 스터디 1주차

🎮 웹 게임을 만들며 배우는 React
1주차: 구구단


1. React를 쓰는 이유?

사용자 인터페이스 및 양질의 사용자 경험을 제공할 수 있으며 싱글 페이지 애플리케이션(SPA), 즉 한 개의 페이지로 이루어진 애플리케이션을 만드는 데 용이하다. 또한, 데이터와 화면의 일치를 리액트가 자동으로 도와준다. 마지막으로 중복되는 컴포넌트를 하나로 묶어주는 것이 가능하여 유지보수가 편리하다는 장점 또한 있다.



2. 컴포넌트 생성

코드가 비효율적으로 느껴질 수 있으나, 이는 리액트의 동작 원리를 알아보기 위함이다.
https://ko.reactjs.org/docs/cdn-links.html 에서 CDN 링크를 가져왔다.

이때

<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>

이는 react가 동작하기 위한 핵심적인 파일이 들어 있는 자바스크립트이며

<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

이 react-dom은 리액트 코드를 웹에 붙여주는 역할이라고 이해하면 된다.

<!DOCTYPE html>
<html>
    <head>
        <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
        <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
        <body>
            <div id="root"></div> <!-- 결과: <div id="root"><button>Like</button></div> -->
            <script> 
                const e = React.createElement;
                
                class LikeButton extends React.Component {
                    constructor(props) {
                        super(props);
                    }

                    render() {
                        // LikeButton을 화면에 어떻게 표시할 것인지
                        return e('button', null, 'Like'); // <button>Like</button>을 만들겠다!
                    }
                }
            </script>
            <script>
                ReactDOM.render(e(LikeButton), document.querySelector('#root')); // 컴포넌트를 root 내에 그림
            </script>
        </body>
    </head>

</html>

예측한대로 button이 생성되었다!
이때 button에 onClick 속성을 부여해 보자. (이때 Html의 속성을 JS로 표현할 시에는 Camel Case를 이용해야 한다.)

                    render() {
                        // LikeButton을 화면에 어떻게 표시할 것인지
                        return e('button', {onClick: () => {console.log('clicked')}, type: 'submit'}, 'Like'); // <button>Like</button>을 만들겠다!
                    }


개발자 도구의 콘솔 로그에 clicked가 남는다.




이제 상태(state)를 변경해 보자. 이때 상태는 바뀌는 부분, 또는 바뀔 수 있는 부분을 의미한다. 버튼을 클릭하면 Like를 Liked로 변경하자.

                    constructor(props) {
                        super(props);
                        this.state = { 
                            // 상태
                            liked: false,
                        };
                    }

                    render() {
                        // LikeButton을 화면에 어떻게 표시할 것인지
                        return e('button', {onClick: () => {this.setState({ liked: true })}, type: 'submit'}, 
                            this.state.liked === true ? 'Liked' : 'Like',); // <button>Like</button>을 만들겠다!
                    }
                }

클릭 시에 상태에 따라 Like가 Liked로 변한다. 상태를 데이터라고 가정했을 시에 데이터를 화면에 보여주는 것의 예시라 할 수 있다.



3.JSX와 바벨(babel)

최신 문법 등을 JS에서 사용할 수 있게 해 주는 babel을 이용한다.

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

그러면 다음과 같이 JS 내에서 html 태그 문법의 사용이 가능하다.

                    render() {
                        // LikeButton을 화면에 어떻게 표시할 것인지
                        return <button type="submit" onClick={() =>{this.setState({ liked: true })}}>
                        	{this.state.liked === true ? 'Liked' : 'Like'}
                        </button>
                        // JSX
                    }
                }
            </script>
            <script>
                ReactDOM.render(<LikeButton />), document.querySelector('#root')); // 컴포넌트를 root 내에 그림
            </script>


이때 JSX라는 개념이 등장하는데, 이 JSX는 JS + XML의 개념이라고 한다.

4. 구구단

        <body>
            <div id="root"></div> <!-- 결과: <div id="root"><button>Like</button></div> -->
            <script type="text/babel"> 
                class GuGudan extends React.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 ({
                                result: '정답!',
                                first: Math.ceil(Math.random() * 9),
                                second: Math.ceil(Math.random() * 9),
                                value: '',
                            });
                        }

                        else {
                             this.setState({
                                result: '땡!',
                                value: '',
                        })  
                        }
                    };

                    onChange = (e) => {
                        this.setState({ value: e.target.value })
                    };

                    render() {
                        return (
                            <div>
                                <div> {this.state.first} 곱하기 {this.state.second}? </div>
                                <form onSubmit={this.onSubmit}> 
                                    <input type="number" value={this.state.value} 
                                        onChange={this.onChange}/>
                                    <button>입력!</button>
                                </form>
                                <div>{this.state.result}</div>
                            </div>
                        );
                    }
                } 
            </script>
            <script type="text/babel">
                ReactDOM.render((<GuGudan />), document.querySelector('#root')); // 컴포넌트를 root 내에 그림
            </script>
        </body>

+)

이때

이와 같이 쓸데없는 div를 없애고 <>...</> 만으로 처리할 수 있다.

++)

constructor... 부분을 제외하고, state만 선언해서 사용하는 것이 가능하다.

+++)
이전의 상태를 표현할 시에는 다음과 같다.

                        if(parseInt(this.state.value) === this.state.first * this.state.second) {
                            this.setState ((prevState) => { // 이전 상태 표현
                                return {
                                result: prevState.first + ' X ' + prevState.second + ' = ' + prevState.value + ' 정답! ',
                                first: Math.ceil(Math.random() * 9),
                                second: Math.ceil(Math.random() * 9),
                                value: '',
                            }
                            });
                        }
                        // 이전 state로 새로운 state 값을 만들 때에는 return을 사용

++++)
입력 후 focus를 주려면 다음과 같다.

                        if(parseInt(this.state.value) === this.state.first * this.state.second) {
                            this.setState ((prevState) => { // 이전 상태 표현
                                return {
                                result: prevState.first + ' X ' + prevState.second + ' = ' + prevState.value + ' 정답! ',
                                first: Math.ceil(Math.random() * 9),
                                second: Math.ceil(Math.random() * 9),
                                value: '',
                            }
                            });
                            this.input.focus();
                        }
                        // 이전 state로 새로운 state 값을 만들 때에는 return을 사용

                        else {
                             this.setState({
                                result: '땡!',
                                value: '',
                        })  
                             this.input.focus();
                        }
                    };

                    onChange = (e) => {
                        this.setState({ value: e.target.value })
                    };

                    input; 
                    onRefInput = (c) => { this.input = c; }; 
                    // state가 바뀔 때마다 render가 실행되므로 함수를 바깥에 선언하는 것이 좋다.
 
                    render() {
                        return ( 
                            <>
                                <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}/>


추가

1.


3번 항목을 수강하던 도중 이와 같은 오류가 발생했다. element를 읽을 수 없어 발생하는 오류라고 한다.

ReactDOM.render 뒤에 괄호가 빠져 있었다. 😥

2.

1.7강 과제

{...}

result: this.state.first + ' X ' + this.state.second + ' = ' + this.state.value + ' 정답! ',

{...}


📖 이용 강의
https://inf.run/gcb2 웹 게임을 만들며 배우는 React

좋은 웹페이지 즐겨찾기