React 이벤트 처리
1. 기본 문법
React에서 이벤트를 처리하는 방식은 DOM 엘리먼트에서 이벤트를 처리하는 방식과 거의 비슷하지만 아래와 같은 문법의 차이가 있습니다.
React의 이벤트는 소문자대신 CamelCase를 사용해서 표기합니다.
JSX를 사용해서 문자열이 아닌 함수로 이벤트 핸들러를 전달합니다.
HTML
<button onclick="activateLasers()">
Activate Lasers
</button>
React
<button onClick={activateLasers}>
Activate Lasers
</button>
2. action, onsubmit
또한 React에서는 false를 반환해도 기본 동작(form에서의 action 호출과 같은)을 방지할 수 없는데, 방지하려면 preventDefault를 명시적으로 호출해주어야 합니다.
HTML
<form onsubmit="console.log('You clicked submit.'); return false">
<button type="submit">Submit</button>
</form>
React
function Form() {
function handleSubmit(e) {
e.preventDefault();
console.log('You clicked submit.');
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
e.preventDefault()란?
위 코드에서 HTML은 버튼이 눌렸을 때 onsubmit이 호출되고, return false로 인해 action이 발생하지 않지만, React에서는 return false를 작성할 수 없기 때문에, onSubmit이 발생했을 때 e.preventDefault()를 명시적으로 호출함으로 action이 발생되는 것을 막아 리렌더링이 되는 것을 막을 수 있습니다. return false와 같은 역할을 하는 셈이죠.
HTML에서의 Form은 action 속성과 onsubmit 이벤트 핸들러가 사용되는데,
action이 하는 역할은 form 데이터를 처리할 프로그램의 URI를 지정해서 폼 데이터를 전송한 후 특정 브라우저로 이동시킬 수 있습니다.
onsubmit이 하는 역할은 form 태그 내부에서 type=submit으로 지정된 엘리먼트의 이벤트가 발생했을 때 그 이벤트를 처리하는 역할을 합니다.
순서는 아래와 같습니다.
Button이 눌림! -> onsubmit()함수 호출! -> return false/true 여부에 따라 action 발생!
버튼 클릭으로 인한 페이지 이동을 원할 경우 true를 작성하고, 그렇지 않으면 false를 작성해주는 것이죠.
3. bind
리엑트에서의 바인딩에 대해 설명하기에 앞서 자바스크립트의 바인딩에 대해 먼저 알아보아야 합니다.
자바스크립트에서 객체 안 메서드의 this는 그 메서드가 포함된 object를 가리키게 됩니다.
var obj = {
prop: 'Hello',
sayHello: function() {
console.log( this.prop );
}
};
obj.sayHello(); //"Hello"
위의 코드에서 sayHello 메서드 안의 this는 obj의 객체가 되어 obj.prop인 Hello를 전달받아 콘솔 로그를 찍게 됩니다.
위의 예제에서 obj.sayHello()를 호출할 때는 정상적으로 출력이 되지만 reference에 담고 나서 출력을 해보면 undefiend가 출력됩니다.
왜? 이유는 변수 reference에 객체가 담길 때 obj와의 관계가 상실되기 때문입니다!
이때 필요한 것이 바인딩으로,
obj.sayHello를 연결할 때 obj라는 객체까지 바인딩시켜서 보내게 되면 정상적으로 변수에 obj 객체가 저장이 됩니다!
리엑트로 돌아가서,
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 콜백에서 `this`가 작동하려면 아래와 같이 바인딩 해주어야 합니다.
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')
);
위와 같은 코드가 있을 때 render()하는 부분에서 버튼의 onClick 이벤트에 handleClick함수를 연결시킨 것을 확인할 수 있습니다. this.handleClick, 즉 Toggle 컴포넌트의 handleClick() 메서드를 연결시킨 것이지요.
handleClick()함수에서는 setState를 호출해 isToggleOn 값을 바꾸어서 버튼이 눌렸는지, 눌리지 않았는지 확인하는데요.
이때 Toggle이라는 컴포넌트가 호출되고 버튼의 이벤트로 인한 콜백이 정상적으로 작동되려면 Toggle이라는 자신의 객체를 bind 시켜서 넘기도록 생성자 측에서 명시적으로 표시해주어야 합니다!
사실 this를 명시적으로 표현하면서 바인딩을 시키는 것이 불편하게 느껴질 수 있는데, 다른 직관적인 표현으로는 생성자를 사용하지 않는 클래스 필드를 사용하는 것입니다.
class LoggingButton extends React.Component {
// 생성자가 없습니다
state = {isToggleOn: true};
// 이 문법은 `this`가 handleClick 내에서 바인딩되도록 합니다.
// 주의: 이 문법은 *실험적인* 문법입니다.
handleClick = () => {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<LoggingButton />,
document.getElementById('root')
);
위와 같이 constuctor가 없어지고, 클래스 내부의 함수들은 화살표 함수로 표현하여 자동적으로 b바인딩이 될 수 있게끔 합니다.
콜백이 하위 컴포넌트에서 props로서 전달된다면 그 컴포넌들은 추가로 다시 렌더링을 수행하게 되고, 성능 저하가 일어날 수 있기 때문에 생성자(constructor) 안에서 바인딩 하거나, 클래스 필드를 사용하는 것을 권장하는 편입니다.
참고 사이트
https://ko.reactjs.org/docs/handling-events.html
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=dilrong&logNo=221542329638
'FrontEnd > React 기본' 카테고리의 다른 글
[React] React.js 강좌 7. 조건부 연산자 (0) | 2021.11.25 |
---|---|
[React] React.js 강좌 6. Error Catch (0) | 2021.11.25 |
[React] React.js 강좌 4. 생명주기 이벤트 (0) | 2021.11.18 |
[React] React.js 강좌 3. Fragments (0) | 2021.11.18 |
[React] React.js 강좌 2. 클래스형 Props & State 정리 (2) | 2021.11.15 |