이벤트 처리하기
React 엘리먼트에서 이벤트를 처리하는 방식은 DOM 엘리먼트에서 이벤트를 처리하는 방식과 매우 유사합니다. 몇 가지 문법 차이는 다음과 같습니다.
- React의 이벤트는 소문자 대신 캐멀 케이스(camelCase)를 사용합니다.
- JSX를 사용하여 문자열이 아닌 함수로 이벤트 핸들러를 전달합니다.
React 공식 문서에서 설명한 위의 내용을 아래 코드 예제로 확인해보자.
HTML에서는 아래와 같다.
<button onclick="activateLasers()">
Activate Lasers
</button>
React에서는 어떤지 아래 코드를 보자.
<button onClick={activateLasers}>
Activate Lasers
</button>
일단 onclick이 onClick으로 camelCase 형식으로 표기된 것을 한 눈에 볼 수 있다.
onClick에 전달한 내용도 따옴표로 전달하지 않고 {}를 사용해 전달한다.
또 다른 차이점은, 기존에 false를 반환해 기본 동작을 막는 것을 React에서는 사용할 수 없다.
React에서 기본 동작을 막기 위해서는 반드시 preventDefault를 명시적으로 호출해야 한다.
아래 예제는 일반 HTML에서 우리가 클릭 동작을 막을 때 사용하는 방법이다.
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
false를 리턴해 클릭을 해도 이벤트가 발생하지 않도록 막을 수 있다.
React에서는 아래처럼 작성해야 이벤트를 막을 수 있다.
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
ActonLink 컴포넌트의 handleClick 메서드에서 사용하는 e는 합성 이벤트이다. React는 W3C 명세에 따라 합성 이벤트를 정의하기 때문에 브라우저 호환성에 대해 걱정하지 않아도 된다.
React를 사용할 때 DOM 엘리먼트가 생성된 후 리스너를 추가하기 위해 addEventListener를 호출할 필요 없이 엘리먼트가 처음 렌더링될 때 리스너를 제공하면 된다.
ES6 클래스를 사용해 컴포넌트를 정의할 때, 이벤트 핸들러를 만드는 일반적인 패턴은 클래스의 메서드로 만드는 방법이다.
아래의 코드를 보자.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'On' : 'Off'}
</button>
);
}
}
ReactDOM.render(<Toggle />, document.getElementById('root'));
처음으로 주목할 constructor 내부의 "this.handleClick = this.handleClick.bind(this)" 부분이다.
컴포넌트를 생성한 다음 handleClick을 사용할 때 위의 바인드를 하지 않으면 handleClick 내부의 this.setState에서 this는 undefined가 될 것이다.
이런 this에 대해 공부해야 할 것이 많아지기 때문에 후에 React에서는 hook을 발표해 함수형 컴포넌트 사용을 장려하고 있다.
이벤트 핸들러에 인자 전달하기
보통 루프에서 이벤트 핸들러를 사용할 때 우리는 매개변수를 사용해야 하는 상황이 많이 발생할 것이다. 예를 들면, 테이블의 행을 삭제하는 기능을 만들기 위해서는 해당 행의 id를 매개변수로 전달해주어야 할 것이다.
React에서는 이벤트 핸들러에 매개변수를 어떻게 전달하는지 확인해보자.
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
위의 두 줄은 같은 동작을 한다.
Arrow function을 사용하면 e 인자가 가장 뒤에 사용되고, bind를 사용하면 this를 가장 처음에 사용되고 추가 인자를 뒤에 사용하는 부분만 주의해서 사용하면 된다.