안녕하세요.
Hynn 입니다.
이번 포스팅에서는 React 에서 이벤트를 어떻게 처리하는지에 대해 알아보도록 하겠습니다.
DOM Elemenet 와 비슷하지만, 조금 다른 특징을 가지고 있기 때문에 이에 대해서도 인지를 하면 보다 효율적으로 작성이 가능합니다.
그럼 시작하겠습니다.
==========
==========
1. React 의 이벤트는 소문자 대신 CamelCase 를 사용합니다.
React 에서 이벤트 표기는 CamelCase 를 사용하여 표기해야 합니다.
CamelCase 는 비단 React 뿐 아니라, Programming 언어에서 일반적으로 사용되는 표기법입니다. 이것은 여러개의 단어를 하나의 이름으로 결합하고, 첫번째 단어만 소문자로, 그리고 난 뒤 각 단어의 첫글자를 대문자로 작성하는 것입니다. 물론 이는 Programming 언어에서 "관습" 이기때문에, 첫번째 단어역시 첫글자를 대문자로 표기해도 관계는 없지만, 일관성 있는 표기를 위해 약속된 것으로 이해하면 보다 쉽습니다.
즉 표기한다면 아래와 같이 표기할 수 있습니다.
사소한 차이지만, 코드의 통일성을 위해 모두 지켜져야 하는 부분이라고 생각합니다.
가령 예를 들면, 아래와 같이 기존과 React 의 이벤트 핸들러 작성시 CamelCase 를 표기한다고 이해하시면 좋습니다.
1)기존 작성의 예
<button onclick="handleClick()">Click</button>
2) React 작성의 예
<button onClick={handleClick}>Click</button>
2. 문법은 JSX, 문자열이 아닌 함수로 이벤트 핸들러를 전달해야 합니다.
즉, 기존의 JavaScript EventHandler 는 아래와 같이 작성을 했었습니다.
handleClick = (e) => {
console.log('event')
}
addEventListener('click', handleClick)
<button onclick=handleClick()>Click me!</button>
위와 같이, JavaScript 에서 위와 같이 설정하거나, HTML 에서 onclick 이벤트를 추가하여 작성을 하는 방식이였습니다.
하지만 이 방식은 React 에서는 조금 다르게 표기합니다.
먼저, React 에서의 이벤트 핸들러로써, 함수를 전달하면 JSX 구문을 사용하여, 컴포넌트 코드에서 함수를 바로 정의할 수 있습니다.
아래와 같은 예시로 말입니다.
const handleClick = () => {
console.log("Event")
}
그리고 난뒤, 함수를 직접 이벤트 핸들러에 전달할 수 있습니다.
<button onClick={handleClick}>Click</button>
이를 Class Component 에도 적용할 수 있습니다.
이전 포스팅에서 다루었던, Life-Cycle 에서의 "Updating" 에 해당하도록 작성할 수도 있습니다.
하지만 아래의 handleClick 은 Updating 에 해당하지 않습니다. 왜일까요?
class Test extends React.Component {
handleClick() {
console.log('Event')
}
render() {
return (
<button onClick={this.handleClick}>Click</button>
)
}
}
이유는 간단합니다. 이 method 는 State, Props 중 그 어떤것도 상태를 업데이트하거나 값을 전달하고 있지 않고 있기 때문입니다.
만약에 아래와 같이 작성한다면 Life-Cycle 중 업데이트에 해당할 수도 있습니다.
예시를 적용하면 아래와 같습니다.
class Test extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0
}
}
handleClick() {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
<p>clickCount {this.state.count} times.</p>
<button onClick={this.handleClick.bind(this)}>Click</button>
</div>
)
}
}
3. React 의 eventHandler 에는 반드시 포함되어야 하는 요소가 존재합니다.
바로 "e.preventDefault" 를 명시적으로 포함해야 합니다.
React 에서는 "false" 를 반환하더라도 기본 동작을 방지할 수 없기 때문입니다. 반드시 "e.preventDefault" 를 명시적으로 호출해야 기본 동작을 방지할 수 있습니다. 이는 예를 들어 HTML 에서 Form 과 같이 제출해야하는 양식을 사용할 때, "false" 더라도 이것을 명시적으로 호출하지 않는다면, 동작을 방지할 수 없기 때문입니다.
이를 반영한 예시는 아래와 같이 작성할 수 있습니다.
class Test extends React.Component {
handleClick(e) {
e.preventDefault()
}
render() {
return (
<a href="#" onClick={this.handleClick}>Click</a>
)
}
}
즉, 기존의 DOM 에서는 eventHandler 에서 return 값이 "false" 일 경우에는, 이벤트의 동작을 방지할 수 있었지만,
React 에서는 위와 같은 방법이 적용되지 않기 때문에, "e.preventDefault"가 명시적으로 호출되어야 합니다.
기존의 DOM 에서 적용하는 방법과는 다르게 이벤트를 처리하고 있기 때문에, 이러한 작성은 반드시 필수적으로 이루어져야 합니다.
4. addEventListener 를 호출하지 않아도 사용할 수 있습니다.
기존의 JavaScript 에서는 DOM 요소에 이벤트를 추가하려면 "addEventListener" 를 사용해야 했습니다.
아래와 같이 말입니다.
const myBtn = document.getElementById('Btn')
myBtn.addEventListener('click', ()=> {
console.log('event')
})
하지만, React 에서는 이러한 addEventListener 를 호출할 필요가 없습니다. 물론 불가피할 경우 호출해야 할 수도 있지만,
일반적으로는 그렇지 않습니다. 바로 React 에서 Component 에 eventHandler 를 정의하고, DOM 요소에 "Props" 로 전달할 수 있기 때문입니다.
즉, 더욱 간결하게 이벤트를 추가할 수 있습니다.
아래와 같이 말입니다.
class Test extends React.Component {
handleClick() {
console.log('event')
}
render() {
return (
<button onClick={this.handleClick}>Click</button>
)
}
}
하지만 여기서 주의해야 할 부분은 바로 "This" 입니다.
5. This bind 처리 주의하기
즉, JavaScript 에서 우리가 알고 있는 this, 즉 class method 에서는 기본적으로 binding 이 처리되어 있지 않습니다. 즉 단순히 bind 를 처리하지 않고, 위와 같은 코드를 실행하게 되면, onClick 에 있는 "this"는 "undefined"가 되므로, 이 이벤트는 동작하지 않습니다.
이를 위해, bind 처리하거나, 다른 방식으로 작성을 해야 합니다.
제 개인적으로는 Arrow Function 이 사용하기 편하지만, 단점도 존재하므로, 가급적 2번의 예제로 작성하는 것을 권장합니다.
1) Arrow Function 으로 작성하기
아래의 예제처럼, "handleClick" method 자체를 arrow function 으로 작성하는 방법입니다. 이렇게 작성할 경우, onClick 에서 "this.handleClick" 그대로 작성을 할 수 있습니다.
하지만, 이러한 경우, Class Component 가 랜더링 될 때마다, 다른 콜백이 생성되는 문제가 발생할 수 있습니다.
일반적으로는 문제가 발생하지 않을 수 있지만, 만약 Component 에서 하위 Component 로 함수를 Props 로 전달할 수도 있습니다.
이러한 경우, 아래의 예제에서, Button 이 랜더링 될 때마다 "새로운"함수가 생성되기 때문입니다.
이러한 생성이 반복될 경우, 이는 결과적으로 전체 Application 의 성능에 영향을 미치게 됩니다.
결과적으로 React 에서는 효과적인 작동을 위해 Props 나 State 가 변경되는 점을 찾아, 랜더링을 다시하지만, 이로 인해 변경된 점이 없더라도 다시 랜더링을 수행하므로, 이는 결과적으로 성능에 영향을 미칠 수 있습니다.
class Test extends React.Component {
handleClick = () => {
console.log('event')
}
render() {
return (
<button onClick={this.handleClick}>Click</button>
)
}
}
2) Bind 처리하기
만약 이를 Bind 처리를 한다면, 아래와 같이 bind 처리를 할 수 있습니다.
물론 Constructor 를 사용하지 않고, 이벤트 자체에서 bind 처리도 할 수 있지만, 전체적 코드의 일관성을 위해 constructor 를 작성하고,
그 내에 bind 처리를 하는 것이 더욱 깔끔해 보일 뿐 아니라,
1번 예제에 비해 성능에 영향을 미치지 않기 때문에, 가장 적합한 사용방법이라고 할 수 있습니다.
만약 onClick 내에 bind 처리를 바로한다면 두번째 예제처럼 작성할 수도 있습니다.
class Test extends React.Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
console.log('event')
}
render() {
return (
<button onClick={this.handleClick}>Click</button>
)
}
}
//Bind 바로 처리하기
<button onClick={this.handleClick.bind(this)}>Click</button>
6. 이벤트 핸들러에 인자(매개변수) 전달하는 방법
일반적으로 이러한 매개변수를 전달할 때는, 루프 내에서 전달하는 것이 일반적입니다.
여기서도, Arrow function 으로 작성했는지, 혹은 bind 처리를 했는지에 따라 작성방법이 달라집니다.
하지만 차이점은 존재합니다.
바로 Arrow function 의 경우, 인자를 "명시적"으로 전달해야 합니다. 하지만 bind 처리를 했을 경우, 추가 인자가 자동으로 전달됩니다.
작성예시는 아래와 같습니다.
// Arrow Function
class Test extends React.Component {
handleClick = (e1, e2) => {
console.log(e1,e2)
}
render() {
return (
<button onClick={() => this.handleClick('Hello', 'World')}>Click</button>
)
}
}
// Bind
class Test extends React.Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this, 'Hello', 'World')
}
handleClick(e1, e2) {
console.log(e1, e2)
}
render() {
return (
<button onClick={this.handleClick}>Click</button>
)
}
}
이벤트를 처리하는 데 있어서도, 기존의 JavaScript 와 JSX 문법을 사용하는 React 는 차이점이 존재합니다.
기본적으로 작동하는데는 큰 차이가 없을수도 있겠지만, 이러한 작성의 차이로 인해 발생하는 결과물은 크게 바뀔 수 있고, 나아가 성능의 영향을 미치는 중요한 요소가 될 수 있기 때문에, 작성에 주의가 필요합니다.
감사합니다.
'개발공부일지 > React' 카테고리의 다른 글
React - List & Key 사용하기 (0) | 2023.03.06 |
---|---|
React - 조건부 랜더링 (0) | 2023.02.28 |
React - 생명주기(Life Cycle) 및 State 알아보기 (0) | 2023.02.27 |
React - Component & Props 이해하기 (0) | 2023.02.24 |
React - Element 단위 이해하기 (1) | 2023.02.23 |
댓글