🕹 이벤트 다루기
React에서 이벤트를 처리하는 것은 DOM element에서 처리하는 것과 굉장히 비슷합니다. 둘은 몇가지 차이점이 있습니다.
- React의 이벤트는
lowercase
대신camelCase
로 이름을 짓습니다. - 이벤트 핸들러를 함수로 전달할 때 문자열 대신 JSX를 사용합니다.
HTML:<button onclick="activateLasers()">
Activate Lasers
</button>---React:<button onClick={activateLasers}>
Activate Lasers
</button>
또 다른 차이점은 React에서는 return false;
를 해도 이벤트의 기본 동작을 막지 못합니다. 기본 동작을 막기 위해서는 preventDefault
를 호출해야 합니다. <a>
태그의 클릭 했을 때 href 속성 값으로 이동하는 기본 동작을 막고 console.log()
하는 예제 입니다.
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('This link was clicked.');
} return (
<a href="#" onClick={handleClick}>
Click me!
</a>
);
}
handleClick()
의 인자 e
는 합성 이벤트입니다. React는 W3C 에 따라서 합성 이벤트를 정의 하기때문에 브라우저 간 호환성 걱정을 안 해도 됩니다.
React를 사용할 때, DOM element가 생성된 후에 리스너(Listener) 를 추가하기 위해 addEventListener
를 호출할 필요가 없습니다. 대신에 element 가 처음 렌더링 됐을 때 리스너를 부여하면 됩니다.
ES6 Class
를 이용해서 컴포넌트를 정의 할 때, 흔히 이벤트 핸들러를 클래스의 메소드로 작성합니다. 유저가 ON / OFF 를 껏다 킬 수 있는 버튼을 렌더링하는 예제 입니다.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {
isToggleOn: false,
};
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')
);
JSX 콜백 함수 안 this
의 의미를 생각해야합니다. JS에서 클래스 메소드는 기본적으로 바인딩을 하지 않습니다. 만약 this.handleClick
를 바인딩 하지 않고 onClick
에게 넘겨준다면, 함수가 호출 될 때 this
는 undefined
로 될 것입니다.
이것은 React 만의 특별한 동작이 아닙니다. 이것은 JS에서 함수가 작동하는 방법 입니다. 기본적으로 onClick={this.handleClick}
처럼 ()
없이 메소드를 참조한다면, 메소드를 바인딩 해야합니다.
bind
를 호출하는 것이 싫다면, 다르게 this
를 가지는 두 가지 방법이 있습니다. 첫 번째로 public class field
문법을 사용한다면 바인딩 할 수 있습니다.
class LoggingButton extends React.Component {
handleClick = () => {
console.log('this is:', this);
} render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
이 문법은 Create React App
로 프로젝트를 만들면 기본적으로 사용 가능합니다. 만약 public class field
문법을 사용하지 않는다면 콜백 함수 안에서 화살표 함수(Arrow function)
를 사용하면 됩니다.
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
} render() {
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
이 문법의 문제점은 LoggingButton
이 렌더링 될 때마다 다른 콜백 함수가 생성 된다는 것 입니다. 대부분의 경우는 상관 없지만 만약 콜백 함수가 하위 컴포넌트에게 props
로 넘겨진다면 하위 컴포넌트가 다시 추가 렌더링을 할 수도 있습니다.
이러한 퍼포먼스 문제를 방지 하기 위해 생성자에서 바인딩을 하거나 클래스 필드 문법을 추천합니다.
🤾♂️ 이벤트 핸들러에 인자 넘기기
루프 안에서, 흔히 이벤트 핸들러에 추가 인자를 전달하기를 원합니다. 행 ID 를 삭제하는 예제입니다.
<button onClick={(e) => this.deleteRow(id, e)}
Delete Row
</button>// Arrow Function</button onClick={this.deleteRow.bind(this, id)}>
Delete Row
</button>// Function.prototype.bind
위 두 줄은 같습니다. 그리고 각각 화살표 함수
와 Function.prototype.bind
를 사용하고 있습니다.
두 가지 케이스 모두 React 이벤트를 나타내는 e
인자가 ID 뒤에 두 번째 인자로 전달됩니다. 화살표 함수 에서는 e
인자를 명시해야 하지만, Function.prototype.bind
를 사용할 경우 추가 인자가 자동으로 전달됩니다.
📚 정리 및 참고 자료
- React에서 이벤트의 기본 동작을 막기 위해서는
preventDefault
를 호출해야 합니다. - React 에서 이벤트를 처리할 때
this
를 위해 바인딩 해야 하지만public class field
문법 또는화살표 함수
를 사용하면 바인딩을 명시 하지 않아도 됩니다.