[React] 웹 게임-1 구구단

ji_silver·2020년 7월 11일
0

[React] 웹 게임

목록 보기
1/8
post-thumbnail

1. 첫 리액트 컴포넌트

  • create-react-app없이 html로 컴포넌트 만들기
  • lecture 디렉터리 만들고 그 안에 index.html 생성

index.html

// react, reactDom
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
    // root에 리액트 넣기
    <script>
        const e = React.createElement; //html 태그를 만들어주는 함수

        class LikeButton extends React.Component {
            constructor(props) {
                super(props);
            }

            render() {
                return e('button', null, 'Like'); //<button>Like</button> 
            }
        }
    </script>
    <script>
        ReactDOM.render(e(LikeButton), document.querySelector('#root')); // ReactDOM은 웹에 실제로 반영시켜줌
    </script>

2. HTML 속성과 상태(state)

  • 상태(state)는 바뀌는 부분, 혹은 바뀔 수 있는 부분
class LikeButton extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            liked: false
        };
    }

    render() {
        return e('button',
            { onClick: () => { this.setState({ liked: true }) }, type: 'submit' },
            this.state.liked === true ? 'Liked' : 'Like'
        );
        // 두번째 자리에 html 속성 넣기
        //<button onclick"() => {console.log('click')}" type="submit">Like</button> 
    }
}

3. JSX와 바벨(babel)

  • 자바스크립트에서 HTML문법을 쓸 수 없지만 babel 사용시 쓸 수 있음
  • script태그에 <script type="text/babel"> 넣어주기
  • JSX (JS + XML) => 닫는 태그를 꼭 해줘야 함(문법이 엄격함)
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
...
</script>
<script type="text/babel">
    class LikeButton extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                liked: false
            };
        }

        render() {
            return <button type="submit" onClick={() => this.setState({ liked: true })}>
                {this.state.liked === true ? 'Liked' : 'Like'}
            </button>;
            // e('button',
            //     { onClick: () => { this.setState({ liked: true }) }, type: 'submit' },
            //     this.state.liked === true ? 'Liked' : 'Like'
            // );
        }
    }
</script>
<script type="text/babel">
    ReactDOM.render(<LikeButton />, document.querySelector('#root'));
</script>

❗ 컴포넌트 장점: 원하는 개수만큼 쉽게 늘릴 수 있음

4. 구구단 만들기

index.html

<div id="root"></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: '',
            };
        }
        render() {
            return (
                <div>
                    <div>{this.state.first} 곱하기 {this.state.second}?</div>
                    <form>
                        <input type="number" value={this.state.value} onChange={(e) => this.setState({ value: e.target.value })} />
                        <button>입력!</button>
                    </form>
                    <div>{this.state.result}</div>
                </div>
            );
        }
    }
</script>
<script type="text/babel">
    ReactDOM.render(<GuGuDan />, document.querySelector('#root'));
</script>

1) 클래스 메서드

onSubmit = (e) => {
    e.preventDefault();
    if (parseInt(this.state.value) === this.state.first * this.state.second) {
        this.setState({
            result: this.state.value + ' 정답',
            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 }) // input태그는 onChange로 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>
    );
}

render() 안에서 쓴 함수는 function 사용 가능.
but! 밖에서 썼다면 무조건 화살표 함수 쓰기 (this가 현재 class를 가리키지 않기 때문)
❗ 밖에서 쓰려면 bind() 함수 써야함

🔥JSXjavascript코드는 웬만하면 섞어쓰지 않기🔥

2) Fragment와 기타 팁들

  • 쓸떼없는 div태그가 감싸져있어서 방해가 됨 -> <>빈태그 또는 <React.Fragment> 로 대신 감싸면 <div id="root"> 다음 바로 태그가 나옴
render() {
    return (
        <div>
            <div>
      		...
      	    </div>
        </div>
    );
}
render() {
    return (
        <React.Fragment>
            <div>
      		...
            </div>
        </React.Fragment>
    );
}
//이 부분 생략 가능 (실무에선 이 방식을 더 많이 사용)
constructor(props) {
    super(props);
}

3) 함수형 setState

  • setState는 비동기이기 때문에 예전 state값으로
    새로운 state를 만들 때 리턴해주는 함수 사용하기
  • prevState는 바꾸기 전 상태값이 들어있음
this.setState((prevState) => {
    return {
      	// 현재 값
        result: prevState.value + ' 정답',
      	// 미래에 바꾸겠다는 state 값
        first: Math.ceil(Math.random() * 9),
        second: Math.ceil(Math.random() * 9),
        value: ''
    };
});

4) ref

  • React로 input에 포커스 주기
onSubmit = (e) => {
    e.preventDefault();
    if (parseInt(this.state.value) === this.state.first * this.state.second) {
        ...this.input.focus();
    }
};

input;

render() {
    return (
        <React.Fragment>
            <input ⭐ref={(c) => {this.input = c;}}
	  	   type="number"
		   value={this.state.value}
		   onChange={this.onChange} />
        </React.Fragment>
    );
}

state 값이 바뀔 때마다 render()함수가 계속 실행되기 때문에 밖으로 빼줌


input;

onRefInput = (c) => {this.input = c;};

render() {
    return (
        <React.Fragment>
            <input ref={this.onRefInput} type="number" value={this.state.value} onChange={this.onChange} />
        </React.Fragment>
    );
}

5. React Hooks

  • React도 Hooks 쓰기를 권장함
  • setState, ref를 안 쓸 때 함수형 컴포넌트를 사용. 하지만 사용할 수 있도록 한 것이 Hooks
  • Hooks는 state가 바뀌면 함수 자체가 재실행 되어 조금 더 느릴 수 있음
<script type="text/babel">
    const GuGuDan = () => {
        //state를 선언하는 방법, state를 분리하기
        const [first, setFirst] = React.useState(Math.ceil(Math.random() * 9));
        const [second, setSecond] = React.useState(Math.ceil(Math.random() * 9));
        const [value, setValue] = React.useState('');
        const [result, setResult] = React.useState('');
        //ref
        const inputRef = React.useRef(); //useRef로 DOM에 접근

        const onSubmitForm = (e) => {
            e.preventDefault();
            if (parseInt(value) === first * second) {
                setResult('정답: ' + value);
                setFirst(Math.ceil(Math.random() * 9));
                setSecond(Math.ceil(Math.random() * 9));
                setValue('');
                inputRef.current.focus();
            } else {
                setResult('땡');
                setValue('');
                inputRef.current.focus();
            }
        };

        const onChangeInput = (e) => {
            setValue(e.target.value);
        };

        return (
            <React.Fragment>
                <div>{first}곱하기{second}?</div>
                <form onSubmit={onSubmitForm}>
                    <input ref={inputRef} onChange={onChangeInput} value={value} />
                    <button>입력!</button>
                </form>
                <div id="result">{result}</div>
            </React.Fragment>
        );
    }
</script>

profile
🚧개발중🚧

0개의 댓글