티스토리 뷰
React element에서 이벤트를 처리하는 방식과 DOM element에서 이벤트를 처리하는 방식을 비교하면서 알아보자.
- React의 이벤트는 소문자 대신 camelCase를 사용한다
- 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>
);
}
React를 사용할 때 DOM 엘리먼트가 생성된 후 리스너를 추가하기 위해 addEventListener를 호출할 필요가 없습니다. 대신, 엘리먼트가 처음 렌더링 될 때 리스너를 제공하면 됩니다.
여기서 e는 합성 이벤트이다. React는 W3C 명세에 따라 합성 이벤트를 정의하기 때문에 호환성을 걱정할 필요가 없다.
+ 합성이벤트(SyntheticEvent)란
이벤트핸들러는 모든 브라우저에서 이벤트를 동일하게 처리하기 위해 SyntheticEvent 객체를 전달 받는다. 그리고 0.14 버전부터 이벤트 핸들러가 false를 반환하더라도 이벤트를 보낸다. 이벤트를 보내지 않으려면 e.stopPropagation() 또는 e.preventDefault()를 호출하면 된다.
SyntheticEvent 객체는 재사용이 가능하다. 그리고 모든 속성들은 이벤트 콜백이 진행 된 이후에 초기화 된다. 따라서 비동기적으로 이벤트 객체에 접근하는 것은 불가능하다.
function onClick(event) {
console.log(event); // => nullified object.
console.log(event.type); // => "click"
const eventType = event.type; // => "click"
setTimeout(function() {
console.log(event.type); // => null
console.log(eventType); // => "click"
}, 0);
// 동작하지 않습니다. this.state.clickEvent 은 null만 가지게 될 것입니다.
this.setState({clickEvent: event});
// 이벤트 속성을 추출할 수 있습니다.
this.setState({eventType: event.type});
}
만약 비동기적으로 이벤트 속성에 접근하려면, event.persist()를 호출하면 된다. 그러면 합성이벤트가 제거되고 유저가 작성한 코드가 유지되어 참조가 허용된다.
ES6 클래스를 사용하여 컴포넌트를 정의할 때, 일반적인 패턴은 이벤트 핸들러를 클래스의 매서드로 만드는 것입니다. 예를 들어, 다음 Toggle 컴포넌트는 사용자가 on과 off 상태를 토글 할 수 있는 버튼을 렌더링 한다.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 콜백에서 `this`가 작동하려면 아래와 같이 바인딩 해주어야 합니다.
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의 의미에 대해 주의 하자. JavaScript에서 클래스 메서드는 기본적으로 바인딩이 되어있지 않다. this.handleClick을 바인딩하지 않고 onClick에 전달하였다면, 함수가 실제 호출될 때 this는 undefined가 된다. 이는 React만의 특수한 동작이 아니며, JavaScript에서 함수가 작동하는 방식의 일부이다. 일반적으로 onClick={this.handleClick}과 같이 뒤에 ()를 사용하지 않고 메서드를 참조할 경우, 해당 메서드를 바인딩 해야한다.
클래스 필드문법을 사용하지 않다면 바인딩을 안하는 방법이 있다. 바로 화살표 함수를 사용하는 것이다.
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 이 문법은 `this`가 handleClick 내에서 바인딩되도록 합니다.
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
이 문법의 문제점은 LoggingButton이 렌더링 될 때마다 다른 콜백이 생성된다. 그래서 대부분의 경우는 문제가 없으나 콜백이 하위 컴포넌트에 props로서 전달된다면 그 컴포넌트들은 추가로 다시 렌더링을 수행한다. 이러한 문제점 때문에 생성자 안에서 바인딩을 하거나 클래스 필드 문법을 사용하는것을 권장한다.
이벤트 핸들러에 인자 전달
일반적으로 루프 내부에서 이벤트 핸들러에 추가적인 매개변수를 전달하는 것이 일반적이다.
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
위 두 줄을 같다. 위는 화살표함수를 사용했고 아래는 Function.prototype.bind를 사용한다. 화살표 함수를 사용하면 명시적으로 인자를 전달해야 하지만 bind를 사용하면 추가 인자가 자동으로 전 된다.
'Web > React' 카테고리의 다른 글
[React] JSX 기초 개념 정리 (0) | 2021.09.01 |
---|---|
[React] 시작하기 (javaScript) (0) | 2021.08.30 |
[React]State and Lifecycle (0) | 2020.07.15 |
[React]Components와 props (0) | 2020.07.15 |
[React]요소(element) 렌더하기 (0) | 2020.07.15 |
- Total
- Today
- Yesterday
- pandas
- TensorFlow
- Deque
- login
- react autoFocus
- error:0308010C:digital envelope routines::unsupported
- BFS
- logout
- Queue
- nextjs autoFocus
- 클라우데라
- next.config.js
- JavaScript
- useState
- mongoDB
- NextJS
- nodejs
- Vue
- django
- read_csv
- Python
- Express
- 자연어처리
- vuejs
- typescript
- useHistory 안됨
- react
- 자료구조
- DFS
- UserCreationForm
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |