이벤트 핸들러 바인딩이란?
컴포넌트(Component)와 이벤트 함수를 연결(bind)하는 것이다.
바인딩하지 않아도 이벤트 함수는 실행이 되지만, 누가(어떤 컴포넌트가) 호출을 했는지 알 수 없다.
바인딩하지 않았는데, 이벤트 함수에서 this.state 또는 this.props를 사용할 경우 undefined로 처리된다.
1. 자바스크립트 함수는 객체이다.
const App = () => {
const nav = useNavigate()
const goTo = () => {
nav('ex-router')
}
const goToWrapper = () => {
goTo()
}
return (
<div>
<nav>
<button onClick={goToWrapper}>가자!!</button>
</nav>
</div>
);
};
- 이벤트 코드를 그대로 전달하는 것이 아닌 함수의 형태로 객체를 전달한다.
const App = () => {
const nav = useNavigate()
const goTo = () => {
nav('ex-router')
}
return (
<div>
<nav>
<button onClick={() => goTo()}>가자2!!</button>
</nav>
</div>
);
};
- 이벤트 할당 부분에 익명함수로 처리하면 함수안에 함수이기에 바로 실행이된다.
1.5 리액트에서 이벤트 핸들링 방법
1. 소문자 대신 카멜케이스 사용
onClick={changename} (x)
onClick={changeName} (o)
<button onClick={activateLasers}>
Activate Lasers
</button>
2. jsx 사용, 문자열이 아닌 함수로 이벤트 핸들러 전달
{onClickHandle}
- 일반적으로 함수를 동작 시킴
- 함수 자체가 전달된다.
- props가 없을 시 함수를 전달할 때 사용한다.
- 함수명 뒤에 ()를 붙이지 않는다.
{onClickHandle()}
- 함수 호출문으로 바로 실행 된다.
- 만일 onClick함수에 호출문을 넣게되면 클릭이벤트가 발생하기도 전에 실행된다.
- 함수에서 반환하는 값이 없다면 undefined가 출력된다.
2. 이벤트 기본 동작 방지
e.preventDefault() 호출
- 리액트에서는 prevetDefault가 명시적으로 호출되어야한다.
- 폼 제출시에는 계속 렌더링이 되는데 계속 렌더링이되는 화면을 막을 수 있다.
- a태그 시 href페이지로 이동하지 않고 넘겨준 값만 사용하게한다.
하나의 웹사이트에 여러개의 이벤트가 존재하고 같은 이벤트라고 하더라도 다르게 동작해야하는 것들이 많아진다.
이벤트 제어가 복잡해지는 근본적인 원인은 html 태그가 중첩된 구조를 가지고 있기 때무인다.
//html
<body>
<div class="divWrapper">
<div class="inner1">
<div class="inner2"></div>
</div>
</div>
</body>
// div태그 안에 > div > div가 구조되어 있다.
//js
const divs = document.querySelectorAll('div')
divs.forEach(box => {
box.addEventListner('click', e => {
console.log(e.currentTarget.className)
})
})
js파일에서 div를 갖고있는 요소를 모두 갖고와서
이벤트가 발생한 타켓을 콘솔에 찍어주는 콜백함수를 실행시켰다.
결과적으로 inner2를 눌렀지만 innner1과 divWrapper도 함께 콘솔에 찍히게 된다.
inner2를 클릭했을 때 해당 블록을 참조하고 있는 실행컨텍스트에 이벤트 버블링 현상이 일어나게 된다.
이벤트 버블링?
브라우저는 inner2의 콜백함수를 실행시키고, 상위에 있는 요소에 동일한 이벤트가 등록되어 있는지 탐색한다.
이 중 동일한 이벤트가 등록되어 있는 요소가 있다면 해당 콜백함수를 실행시킨다.
이벤트 버블링은 특정 요소에서 이벤트가 발생했을 때, 상위에 있는 요소에도 동일한 이벤트가 적용되어 있다면 해당 요소까지 이벤트가 전파되는것을 말한다.
Event.stopPropagation()
사실상 여러개 동일한 요소에 등록된 이벤트의 전파가 어떻게 흘러가는지 파악하기 힘들다. Event.stopPropagation()은 특정 요소에만 실행하고 전파를 막기위해서 사용한다.
//js
const divs = document.querySelectorAll('div')
divs.forEach(box => {
box.addEventListner('click', e => {
e.stopPropagation()
console.log(e.currentTarget.className)
})
})
//react
import React, { useState } from 'react'
function Test() {
const [visible, setIsvisible] = useState(false)
const closeBanner = (e) => {
e.stopPropagation()
setIsvisible(true)
}
return (
<div
onClick={() => alert('당첨!')}
style={{ display: visible ? 'flex' : 'none' }}
>
<button type="button"
onClick={closeBanner}
>닫기</button>
</div>
)
}
export default Test
- setIsvisible(true)는 비동기로 처리되기 때문에 stopPropagation이 없다면 해당 코드는 다시 상위 코드가 먼저 호출된다.
- closeBanner 함수에서 이벤트 객체를 넘겨주고 해당 객체에 stopPropagation을 적용시켜준다.
- 리액트 컴포넌트에서 함수를 짤때 하나의 컴포넌트 내에서 중첩된 이벤트를 잘 살펴야한다.
- 또한 상, 하위컴포넌트에서도 같은 함수를 사용하고 있는지 잘 확인해야한다.
3. 이벤트에서의 this
화살표 함수와 Function.prototype.bind
- 이벤트에서 this를 호출한 경우에 바인딩이 되어 있지 않기 때문에 undefined가 나온다.
- props 전달 시에는 arrow함수를 사용한다.
- 혹은 함수명 뒤에 .bind함수를 사용한다.
4. 이벤트 핸들러에 인자 전달하기
콜백함수 이벤트 핸들러에 인자를 넘기는 코드는 상황마다 각각 다르다.
1). [콜백함수에 어떠한 인자도 넘기지 않을 때]
함수 표현식으로 따로빼서 jsx문법으로 중괄호 안에 변수를 넣어주는 방식을 많이 사용한다.
function Test() {
const onClickHandle = () => {
alert('hello world')
}
return (
<div>
<button
type="button"
onClick={onClickHandle}
>Click Me!</button>
</div>
)
}
export default Test
간단한 문구라면 함수 실행을 inline으로 넣어줘도 괜찮!
//onClick={() => alert('hello world')}
2). [(이벤트 객체가 아닌) 일반적인 인자를 넘길 때]
// name이라는 문자열 파라미터를 받는다.
import React, { useState } from 'react'
function Test() {
const onClickHandle = (name) => {
alert(`hello, ${name}`)
}
return (
<div>
<button
type="button"
onClick={onClickHandle('nimo')}
>Click Me!</button>
</div>
)
}
export default Test
여기서 문제점은 onClick={onClickHandle('nimo')}부분에서 함수 호출을 바로해줬기 때문에 onclick 이벤트가 발생되기도 전에 alert이 먼저 실행되버린다.
콜백함수에서 인자값을 넘겨 줄 때는 함수호출이 아닌 함수 선언식을 사용해야한다.
import React, { useState } from 'react'
function Test() {
const onClickHandle = (name) => {
alert(`hello, ${name}`)
}
return (
<div>
<button
type="button"
onClick={() => onClickHandle('nimo')}
>Click Me!</button>
</div>
)
}
export default Test
3). [이벤트 객체만을 인자로 넘길 때]
이벤트객체란?
이벤트를 만들었을 때 자동으로 만들어지는 객체를 말한다.
이벤트에 대한 정보를 담고 있는 객체이다.
import React, { useState } from 'react'
function Test() {
const onClickHandle = (e) => {//클릭핸들러 함수 또한 인자를 받는 부분을 변경
alert(e.target.value)
}
return (
<div>
<button
type="button"
value={'clickBtn'}
onClick={(e) => onClickHandle(e)}
>Click Me!</button>
</div>
)
}
export default Test
만일 이벤트 객체 하나만을 넘기려고 할때는 줄여도 가능하다.
onClick = {(e) => onClickHandle(e)}
▼
onClick = { onClickHandle }
4). [이벤트 객체와 이벤트 객체가 아닌 인자를 함께 넘길 때]
import React, { useState } from 'react'
function Test() {
const onClickHandle = (e, name) => {
alert(e.target.value)
console.log(name)
}
return (
<div>
<button
type="button"
value={'clickBtn'}
onClick={(e) => onClickHandle(e, 'nimo')}
>Click Me!</button>
</div>
)
}
export default Test
이벤트 객체와 일반 인자를 넘길 때 함수 커링에대해서도 잠깐 살펴보자.
[함수 커링]:
함수 호출 시 여러 개의 인자를 한번에 넘기지 않고, 한 번에 하나의 인자를 넘기고, 함수의 인자를 개수만큼 여러번 호출하는 방식을 말한다.
알아야 할 부분: 일급 객체, 클로저, 렉시컬 스코프, 스코프 체인
import React, { useState } from 'react'
function Test() {
const onClickHandle = name => e => {
alert(e.target.value)
console.log(name)
}
return (
<div>
<button
type="button"
value={'clickBtn'}
onClick={(e) => onClickHandle('nimo')(e)}
// onClick={onClickHandle('nimo')} 이렇게 줄여도 됨
>Click Me!</button>
</div>
)
}
export default Test
댓글