Handling Events
React elements에서의 이벤트 처리는 DOM elements에서의 이벤트 처리와 비슷하다.
다만 약간의 문법적인 차이가 있을 뿐이다.
- React 이벤트는 소문자보다는 카멜 케이스를 이용하여 명명한다.
- JSX를 이용하여 문자열보다는 함수형의 이벤트 핸들러를 전달한다.
HTML의 예는 다음과 같다.
<button onclick="activateLasers()">
Activate Lasers
</button>
React는 이와 조금 다르다.
<button onClick={activateLasers}>
Activate Lasers
</button>
또다른 차이점이라면 React에서는 기본적인 동작을 막기 위해 false를 리턴할 수 없다는 것이다.
대신에 명시적으로 preventDefault
를 호출해야 한다. 예를들어 일반적인 HTML에서는 새로운 페이지가 열리는
기본적인 링크 동작을 막기 위해 아래와 같은 코드를 사용한다.
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
React에서는 위의 코드 대신에 다음과 같이 한다.
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
여기서 e
는 synthetic 이벤트이다. React에서는 W3C의 사양에 따라 이러한 synthetic 이벤트들을 정의한다.
따라서 개발자들은 브라우저간의 호환성을 걱정할 필요가 없다. 더 많은 것을 알고 싶다면 SyntheticEvent의 참조
가이드를 보라.
보통 React를 이용할 때는 DOM elements가 생성된 후 이벤트 리스너를 추가하기 위해 addEventListener
를
호출할 필요가 없다. 대신에 초기 렌더링 되는 시점에 리스너를 제공해주면 된다.
ES6 class를 이용하여 component를 정의한 경우 이벤트 핸들러는 클래스의 메서드로 만드는 것이 일반적이다.
예를들어 아래의 Toggle
component는 사용자가 “ON”이나 “OFF”를 토글할 수 있는 버튼을 렌더링한다.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make this work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
위의 코드에서 JSX callback 내에 있는 this
의 의미에 대해 주의해야 한다. JavaScript에서는 클래스 메소드가
기본적으로 bound 되지 않는다. 만약 this.handleClick
을 bind하는 것을 잊은 상태로 onClick
에 전달했다면
함수가 실제로 호출되었을 때 this
는 undefined
가 된다.
이 것은 React만의 특별한 동작은 아니다. JavaScript에서 함수가 작동하는 방식의 일부이다. 일반적으로onClick={this.handleClick}
처럼 뒤에 ()
가 없는 함수를 참조하는 경우 그 함수를 bind 하는 것이다.
만일 bind
를 호출하는 것이 번거롭다면 이를 해소할 두가지 방법이 있다. 만일 실험적인 속성 초기화 문법을 사용
한다면 callback의 정확한 bind를 위해 속성 초기화를 이용할 수 있다.
class LoggingButton extends React.Component {
// This syntax ensures this is bound within handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
이러한 문법은 React app 생성 시 기본적으로 사용된다.
만일 속성 초기화 문법을 사용하지 않는다면 callback에 화살표 함수를 사용할 수 있다.
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures this is bound within handleClick
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}
이 문법에서의 문제점은 LoggingButton
이 렌더링되는 시점에 서로 다른 각각의 callback이 생성된다는 것이다.
대부분의 경우에 이 것은 문제되지 않는다. 하지만 만일 callback이 prop으로서 하위 component로 전달된다면
이 컴포넌트들은 추가적으로 다시 렌더링 될 수 있다. 따라서 이런 종류의 성능 관련 문제를 피하기 위해서 일반적으로
생성자에서 binding 하거나 속성 초기화 문법을 사용할 것을 권장한다.
'Study > React' 카테고리의 다른 글
React 살펴보기 #8 (0) | 2017.05.15 |
---|---|
React 살펴보기 #6 (0) | 2017.03.27 |
React 살펴보기 #5 (0) | 2017.03.04 |
React 살펴보기 #4 (0) | 2017.02.17 |
React 살펴보기 #3 (0) | 2017.02.11 |