블로그 내용은
Programming with Mosh React Tutorial for Beginners [React js]
을 공부하는 과정에서 작성되었습니다.
<작성 코드>
import React, { Component, Fragment } from 'react';
class Counter extends Component {
state = {
count : 1,
tags: ["tag1", "tag2", "tag3"]
};
render() {
return (
<Fragment>
<span className={this.getBadgeClasses()}>{this.formatCount()}</span>
<button className="btn btn-secondary btn-sm">Increment</button>
<ul>{this.state.tags.map(tag => <li key={tag} >{tag}</li>)}</ul>
</Fragment>
);
}
getBadgeClasses() {
let classes = "badge m-2 badge-";
classes += this.state.count === 0 ? "warning" : "primary"; //엘로우 블루
return classes;
}
formatCount() {
const {count} = this.state;
const x = "ZERO";
return count === 0 ? x : count;
}
}
export default Counter;
이제 사용자가 버튼을 클릭하면 카트에 숫자가 증가하도록 코드를 작성해보자. 바닐라 자바스크립트로는 addEventListener와 비슷한 개념이다.
클릭시 작동되는 함수를 작성하고, 클릭할 버튼을 편집한다.
handleIncrement () { console.log("Increment Clicked", this); // 클릭시 호출될 메서드
<button onClick={this.handleIncrement} className="btn btn-secondary btn-sm">Increment</button>
// Button에 onClick을 이용해서 메서드와 연결
여기서 주의할 부분은 JSX에서는 handleIncrement()가 아닌 handleIncrement으로 코드를 작성시켜야 한다는 점이다. 호출시킨 결과를 넘기는 것이 아니고 클릭할때마다 호출해야하기 때문이다.
위와 같이 작성하면, 결과로는 클릭 시 Increment Clicked는 출력되지만 this는 undefined로 출력될 것이다. 문제를 해결해보자
위와 같은 결과가 나오는 이유는 자바스크립트에서 this가 가리키는 것이 Counter 객체가 될 이유가 없기 때문이다. 왜냐하면 객체 안에 메서드에서 그 메서드가 포함된 object를 가리키는 것이 this이기 때문이다. 그렇기 때문에 메서드와 this의 관계를 위해 "바인딩"을 사용한다.
handleIncrement = () => { console.log("Increment Clicked", this); }
다음과 같이 애로우 함수를 사용하여 바인딩을 구현해주면된다. (생성자를 사용한 기초적인 바인딩은 아래를 참고)
https://ko.reactjs.org/docs/handling-events.html
만약에 매개변수가 있다면 익명함수처리해서 넘겨야한다.
() => handleIncrement(매개변수명)
handleIncrement = () => { console.log("Increment Clicked", this); this.state.count++; }
이제 클릭시 값의 증가를 구현하기 위해 코드를 변경했다.
하지만 실제로는 클릭마다 값이 증가하지 않는다. 이유는 리액트는 동적으로 state를 관리하기 위해서 setState()메서드를 사용하기 때문이다.
handleIncrement = () => { console.log("Increment Clicked", this); this.setState({count: this.state.count + 1}); }
위와 같이 변경해주면 정상적으로 작동하는 것을 확인할 수 있다.
setState()의 특성을 살펴보겠습니다.
render() {
return (
<Fragment>
<span className={this.getBadgeClasses()}>{this.formatCount()}</span>
<button className="btn btn-secondary btn-sm">Increment</button>
<ul>{this.state.tags.map(tag => <li key={tag} >{tag}</li>)}</ul>
</Fragment>
);
}