이벤트 리스닝 : 특정 엘리먼트가 어떤 이벤트를 수신할지 결정하는 것
이벤트 리스너 : 이벤트 리스너란 이벤트가 발생했을 때 그 처리를 담당하는 함수를 가리키며, 이벤트 핸들러(event handler)라고도한다. 지정된 타입의 이벤트가 특정 요소에서 발생하면, 웹 브라우저는 그 요소에 등록된 이벤트 리스너를 실행시킨다.
onclick
, onmouseover
, onsubmit
, onchange
등 전부 소문자로 작성됐던 이벤트 속성들은 리액트 엘리먼트에서는 각각 onClick
, onMouseOver
, OnSubmit
, OnChange
등 카멜 케이스로 작성되어야 한다.// DOM 엘리먼트에서 이벤트 속성 작성 시 전부 소문자로 작성하며
// 속성 값을 문자열로 작성하여 이벤트 핸들러를 전달한다.
<button onclick="activateLasers()">
Activate Lasers
</button>
// 리액트 엘리먼트에서 이벤트 속성 작성 시 카멜케이스로 작성하며
// 속성 값은 문자열이 아닌 표현식을 이용해 함수로 이벤트 핸들러를 전달한다.
<button onClick={activateLasers}>
Activate Lasers
</button>
addEventListener
를 호출할 필요가 없다. 대신, 엘리먼트가 처음 렌더링될 때 리스너를 제공하면 된다.false
를 반환해도 해당 엘리먼트의 기본 동작을 방지할 수 있었지만, 리액트 엘리먼트의 경우 반드시 핸들러가 preventDefault
를 호출해야 한다.// DOM 엘리먼트에서는 핸들러가 false를 반환하면 a 태그의 기본 동작이 방지됨
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
// 리액트에서는 a 태그의 기본 동작을 막기위해서 반드시
// preventDefault를 호출해야한다.
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
onClick
등으로 전달한 이벤트에서 this
를 호출한 경우 바인딩 되어있지 않기 때문에 undefined로 표시된다.💡 이벤트 콜백에서
window
가 아닌undefined
가 나오는 이유는 React가 development 모드에서는 strict mode로 검사를 하기 때문이다. production build 에서는 포함되지 않는다.
onClick={this.handleClick}
과 같이 뒤에 ()를 사용하지 않고 메서드를 참조할 경우, 해당 메서드에 this
를 바인딩 해야한다.// 1. 생성자에서 bind()를 사용하는방법
class LoggingButton extends React.Component {
Constructor(props) {
super(props);
// 콜백에서 `this`가 작동하려면 아래와 같이 바인딩해야 한다.
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
// 2. 사용할 곳에서 bind()를 사용하는 방법
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick.bind(this)}>
Click me
</button>
);
}
}
// 3. 화살표 함수로 직접 호출하는 방법
// 이 방법은 LoggingButton이 랜더링 될 때마다 새로운 함수를 생성하는 문제가 있다.
// 콜백 함수 내에서 재랜더링을 발생시키는 경우 성능 문제가 발생할 수 있다.
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
return (
// 이 문법은 `this`가 handleClick 내에서 바인딩되도록 한다.
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}
// 4. 화살표 함수로 선언하고 바인딩하는 방법
// 이 방법으로 이벤트를 바인딩 하는것을 권장한다.
class LoggingButton extends React.Component {
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
class LoggingButton extends React.Component {
Constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
handleClick(e)
처럼 모든 이벤트 핸들러에는 해당 이벤트에 대한 정보를 담고 있는 이벤트 객체가 매개변수로 전달된다.class ClickEventEx extends React.Component {
constructor(props) {
super(props);
this.clickHandle = this.clickHandle.bind(this);
}
clickHandler(msg) {
console.log(msg);
}
render() {
return (
<button onClick={this.clickHandler("Hi")}>Click</button>
);
}
}
clickHandler()
함수의 명령이 실행된다.onClick={함수이름}
이 아닌 onClick={함수이름()}
으로 이벤트 핸들러를 작성할 경우 clickHandler()
함수를 먼저 실행 한 뒤 리턴 값을 onClick
에 전달하게 된다.clickHandler()
함수를 아래와 같이 함수의 return 값을 함수로 전달하는 방식으로 수정할 경우, 버튼을 눌렀을 때 return 한 함수가 작동한다.clickHandle(msg) {
console.log(msg);
return () => {
console.log("클릭 시 리턴한 함수가 전달된다.")
}
}
화살표함수를 사용하는 방법
<button onClick={(e) => this.clickHandler("Hi", e)}>Click!</button>
bind()
함수를 사용하는 방법
<button onClick={this.clickHandler.bind(this,"Hi")}>Click!</button>
e
인자가 두 번째 인자로 전달된다. 화살표 함수를 사용하면 명시적으로 인자를 전달해야 하지만 bind를 사용할 경우 추가 인자가 자동으로 전달된다.class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {num: 0}
this.increase = this.increase.bind(this);
}
increase(e) {
this.setState({
num: this.state.num + 1
})
}
render() {
return (
<div>
<p>{this.state.num}</p>
<BtnComp onClick={this.increase}/>
</div>
)
}
}
class BtnComp extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<button>Click +</button>
);
}
}
ReactDOM.render(
<Counter/>,
document.getElementById('app')
)
increase()
함수를 실행해야 하는 것은 정확히 말하면 BtnComp 컴포넌트 자체가 아니라 BtnComp의 button 태그다.class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {num: 0}
this.increase = this.increase.bind(this);
}
increase(e) {
this.setState({
num: this.state.num + 1
})
}
render() {
return (
<div>
<p>{this.state.num}</p>
// BtnComp에 clickHandler라는 이름으로 increase()를 props로 전달한다.
<BtnComp clickHandler={this.increase}/>
</div>
)
}
}
class BtnComp extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
// BtnComp에서는 increase() props로 전달받아
// onClick의 이벤트 핸들러로 설정한다.
<button onClick={this.props.clickHandler}>Click +</button>
);
}
}
const ClickCounterButton = props => {
return (
<button onClick={props.handler}>Don`t touch me with your dirty hands!</button>
);
};
class Counter extends React.Component {
render() {
return <span>Clicked {this.props.value} thies.</span>;
}
}
class Content extends React.Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
}
handleClick = (event) => {
this.setState({counter: ++this.state.counter });
}
render() {
return (
<div>
<ClickCounterButton handler={this.handleClick} />
<br/>
<Counter value={this.state.counter}/>
</div>
)
}
}
addEventListener
를 사용하는 전통적인 방법을 사용해야 한다.class Something extends React.Component {
handleMyEvent(e) {
// 이벤트 처리
}
componentDidMount() { // 이벤트 등록
window.addEventListener("someEvent", this.handleMyEvent);
}
componentWillUnmount() { // 이벤트 제거
window.removeEventListener("someEvent", this.handleMyEvent);
}
render() {
return (
<div onSomeEvent={this.handleMyEvent}>Some Event</div>
)
}
}