React 이벤트 처리
React의 이벤트 처리방식은 Vanila JS의 이벤트 처리 방식과 거의 유사하다.
몇 가지 차이만 알고 있으면 된다.
차이 1] 기본 문법
- React 이벤트는 소문자 대신 카멜 표기법(camelCase)를 사용한다
- JSX를 사용하여 문자열이 아닌 함수로 이벤트 핸들러를 전달한다
HTML에서 작성
<button onclick="activateLasers()"> Active Lasers </button>
React에서 작성
<button onClick={activeLasers}> Activate Lasers </button>
이벤트 onclick대신 onClick으로.. 마치 낙타(camel) 혹 처럼 쓴다. " " 문자열 대신 { } 을 사용하여 JSX로 전달한다.
차이 2] 이벤트 기본 동작 방지
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="#" onClck={handleClick}>
Click me
</a>
);
}
HTML 태그 내에 작성한 코드는 false값을 반환해서 태그 기능이 동작 않토록 했으나 React는 그렇게 쓸 수 없다. 그래서 handleClick 함수 안에 preventDefault()를 정의해서 쓰도록 했다.
위 코드는 이벤트 기본동작은 하지 않고, console.log('The link was clicked.')만 찍힌다.
차이 3] 이벤트에서의 this
기본적으로 onClick등으로 전달한 이벤트에서 this를 호출한 경우 바인딩 되어있지 않기 때문에 undefined로 표시된다. ( 쉽게 말해 컴퓨터 입장에서 this가 누굴 가르키는지 알 수 없을 때 "이거다!" 알려주는 개념)
자바스크립트에서의 바인딩(javascript Binding) 참고
리액트 또한 onClick=처럼 뒤에 ()를 사용하지 않고 메서드를 참조할 경우, 해당 메서드를 바인딩 해줘야 한다. 공홈에 예제 이해가 잘 안 돼서.. 다른 예제를 만들어봤다
클릭할 때 마다 글자가 바뀌는 버튼을 하나 만들어보자.
class ButtonBind extends React.Component {
constructor(props) {
super(props);
this.state = { toggle: false };
this.toggleButton = this.toggleButton.bind(this);
}
toggleButton() {
this.setState(state => ({
toggle: !state.toggle
}));
console.log(this);
}
render() {
return (
<div>
<button onClick={this.toggleButton}>
{this.state.toggle ? "ON" : "OFF"};
</button>
</div>
);
};
};
ReactDOM.render(<div><ButtonBind /></div>, document.querySelector('#root'));
constructor에서 toggle을 false 초기 값으로 셋팅한다. 그리고 toggleButton 함수를 onClick 처리 함수로 추가해서 버튼이 클릭 될 때 마다 호출되도록 한다. 마지막으로 toggleButton 함수를 만들고 불릴 때 마다 toggle 스위치를 껐다켰다 하도록 한다.
그러면 'setState' of undefined라는 에러가 발생한다. onClick이 toggleButton 함수를 호출 할 때 this가 선언되지 않아서 발생하는 문제이다.
* render()와 toggleButton()의 this의 차이는 생명주기를 살펴보면 더 명확하다 5. State와 생명주기
제로초님의 글 덕분에 더 잘 이해할 수 있었다..
이건 React만의 특수한 동작이 아니다. JavaScript에서 함수가 작동하는 방식이다. 일반적으로 onClick=과 같이 뒤에 ()를 사용하지 않고 메서드를 참조 할 경우, 해당 메서드를 바인딩 해야 한다고... ( 분명 본 적 있는데 제대로 이해하지 않고 넘어가니, 리액트 공부하면서 더 끙끙거린 것 같다 )
.bind(this)를 꼭 써야할까?
봤다시피.. .bind(this) 코드를 작성하면 코드가 지저분해지고, 코드량도 늘어난다. 신경도 써줘야하니 귀찮다. 그래서 이를 해결 할 수 있는 방법 2가지가 있다.
- 클래스 필드 문법 사용
class LoggingButton extends React.Component {
// 이 문법은 `this`가 handleClick 내에서 바인딩되도록 합니다.
// 주의: 이 문법은 *실험적인* 문법입니다.
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
console.log창에 LogginButton이 찍힘. this가 클래스 내에서 작동하는 것을 볼 수 있다.
this가 handleClick 내에서 바인딩 되도록 해주는 방법이다. 공홈에도 나와있듯이 실험적 문법이어서 bable을 설정해줘야한다.
뭐가 다른지 한참 찾았다; ButtonBind의 예시로 따지자면
toggleButton = () => {
this.setState(state => ({
toggle: !state.toggle
}));
console.log(this);
}
이렇게 바꿔준거다.
2. 콜백에 화살표 함수 사용하기
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 이 문법은 `this`가 handleClick 내에서 바인딩되도록 합니다.
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
이렇게 콜백 함수를 사용할 수도 있다. 이 문법의 문제점은 LogginButton이 렌더링 될 때 마다 다른 콜백이 생성된다는 것이다.
이 방법은 추천 안함!
bind하거나 () ⇒ {} 문법을 사용하면 좋다. 나는 나는 클래스 필드 문법을 많이 사용할 듯 하다.
'JavaScript > React' 카테고리의 다른 글
create-react-app (0) | 2021.03.08 |
---|---|
리액트 시작하기-기본적으로 필요한 툴 (0) | 2021.03.08 |
11. 합성 vs 상속 (0) | 2021.02.05 |
5.1 State 올바르게 사용하기 (0) | 2021.02.01 |
5. State와 생명주기 (0) | 2021.02.01 |