본문 바로가기

Client/React.js

<리액트 기초> 메서드와 함수형 setState

 

 

 이번 장에서는 간단한 구구단 게임을만들며 리액트의 기능들을 학습했다.

 

 

  질문이 각 1부터 9까지 숫자로 랜덤으로 나오고 답을 입력한다. 입력버튼을 누르면 틀리면 땡, 정답이면 정답이라는 문자와 답을 출력하고, 다음 문제가 위에 새로 뜨게 된다.

 

 먼저 지난 장에서와 같이 헤드에 리액트, 리액트돔, 바벨을 넣는다. 그리고 div태그로 root를 만들어준다. 

 

class GuGuDan extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
           ...
        };
    }

    onSubmit=(e) => {
       ...
    };

    onChange=(e) => ...;

    input;

    onRefInput = ...;

    render() {
        return (
            ...
        );
    }
}

 

 첫번째 스크립트문에 클래스를 통해 컴포넌트를 만든다. 클래스의 첫 번째 메서드인 constructor안에 state를 통해 변하는 값들을 입력할 것이다. 

 

 참고로 컴포넌트에서 굳이 constructor을 주지않고 바로 state = {} 으로 변화하는 값들을 선언해도 좋다. constructor을 사용하면 내부에서 함수를 실행하고 그 값을 넣는 등의 세밀한 과정이 가능해진다. 

 

constructor(props) {
    super(props);
    this.state = {
        first:Math.ceil(Math.random() * 9),
        second:Math.ceil(Math.random() * 9),
        value: '',
        result: ''
    };
}

 

 this.state 안에 바뀌는 것들을 객체형식으로 넣어준다. first와 second 에는 초깃값도 필요하므로 따로 넣어준다. 랜덤함수로 0~1 숫자를 구해서 9를 곱했고, Math.ceil로 크거나 같은 숫자 중 가장 작은 값을 정수로 반환하도록 하였다.

 

 value는 사용자의 입력을 받는 곳이고, result는 결과를 출력하는 곳이다.

 

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();
    }
};

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

input;

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

 

 state와 달리 함수들은 메소드 형식으로 클래스에 넣어준다. 함수를 render(){} 부분에 넣어도 되지만 분리하는 것이 더 좋기 때문에 별도로 두었다. 만약 분리하지 않는다면 랜더링이 될 때마다, 즉 변할 때마다 함수가 새로 생기게 될 것이고 이는 매우 낭비이다. 참고로 함수를 따로 뺐으므로 반드시 화살표 함수를 써야한다. 그렇지 않으면 this가 인식을 제대로 하지 못할 것이다.

 

  onSubmit에는 submit 되었을 때의 함수를 만들었다. 먼저 e.preventDefault()를 통해서 기존의 submit 의 기능을 제거한다. 그리고 if문으로 값을 비교하게 하였고, setState로 값을 변하게 하였다. 여기서 정답 시에 우리는 이전에 입력한 값을 반환하도록 할 예정이다. setState는 비동기이므로 내부에서 this.state값을 활용하려면 별도 함수를 만드는 것이 좋다. 

 

 그래서 this.setState안에 prevState라는 임의의 인자를 받는 함수를 만들어서 이전 값을 쓸 수 있게 하였다.

 

 input.focus는 아래에서 별도로 알아보도록 하자.

 

render() {
    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>
    );
}

 

 render 부분을 살펴보자. 렌더부분은 기존에 <div>태그로 감싸야 했는데, 이는 사실 불필요한 태그를 써야하는 것이므로 낭비이다. 이 때 div자리를 비우고 <></>를 사용하면 태그없이 렌더링이 가능하다. 만약 오류가 날 경우 위와 같이 <React.Fragment>를 사용하면 오류없이 태그를 지울 수 있다.

 

 참고로 render부분에는 절대 setState를 넣으면 안된다. 렌더링이 무한반복된다.

 

 form에는 제출 시 onSubmit 메소드를 사용하도록 하였다. input부분이 조금 복잡하다. value는 state에서 지정한 값을 갖게 하였다. 이 input은 onChange가 없으면 값이 입력되지 않음을 알 수 있다. 그래서 onchange메소드를 사용해서 값이 변할 수 있도록한다. 이는 리액트에서 변하는 값을 관리할 수 있도록 한다.

 

 구구단을 입력하고 나서도 input에 포커싱이 유지되도록 하려면 ref를 이용하면 된다. 클래스에 input이라는 임의의 변수를 선언하였다. 그리고 아래에는 임의의 함수를 만들었다. 임의의 인자c를 input에 담도록하였다. 그리고 각 setState가 일어난 후 input.focus()를 일어나게 하여 포커싱되도록 한다.

 

<script type="text/babel">
    ReactDOM.render(<GuGuDan />, document.querySelector('#root'));
</script>

 

 마지막으로 렌더링을 해주면 완성이다.

 


 

 

 

 

참고

 

 

 이 글은 ZeroCho 님의 리액트 무료 강좌를 수강하며 개인적으로 정리하며 쓰는 글입니다.

 

 

 

 

인프런

 

웹 게임을 만들며 배우는 React - 인프런

웹게임을 통해 리액트를 배워봅니다. Class, Hooks를 모두 익히며, Context API와 React Router, 웹팩, 바벨까지 추가로 배웁니다. 초급 웹 개발 프레임워크 및 라이브러리 React 웹 개발 게임개발 온라인 강

www.inflearn.com

 

유튜브

 

리액트 무료 강좌(웹게임)

 

www.youtube.com