React

버블링과 캡처링, form과 Enter 동작

hs-archive 2021. 7. 16. 18:47

https://unsplash.com/@reims

React로 프로젝트를 작성하다가 bubbling 때문에 문제가 생겼다.

 

bubbling과 함께 capturing이란 개념에 대해 배우고

 

문제를 해결해 보자.

 

 

 

 

 


얻어갈 지식

  • 이벤트 버블링, 캡처링
  • form 태그 안에서의 Enter키 동작

 

 

 

 

 

"이벤트 버블링과 이벤트 캡처링"

 

 

아래와 같은 HTML 문서와 js 파일이 있다.

 

<html>
 <body>
  <div>
   클릭 !!
  </div>
 </body>
</html>
const html = document.documentElement
const body = document.body
const div = document.querySelector('div')

div.addEventListener('cliick', function() {
 console.log("DIV")
})

div.addEventListener('cliick', function() {
 console.log("BODY")
})

div.addEventListener('cliick', function() {
 console.log("HTML")
})

 

 

해당 코드로 이루어진 화면에서 유저가 <div> 부분을 클릭하면, 브라우저는 유저가

 

<div>의 onclick 이벤트를 실행하기 위해 클릭한 건지

 

<body>의 onclick 이벤트를 실행하기 위해 클릭한 건지

 

<HTML>의 onclick 이벤트를 실행하기 위해 클릭한 건지 알 수 없다.

 

그래서 브라우저는 다 실행한다.

 

그림과 함께 생각해 보자.

 

그림의 1처럼 <div>를 누르면 <div> <body> <html> 셋 중 어느 것을 눌렀는지 모르므로 셋 다 실행되고

 

2처럼 <body> 영역을 누르면 <body> <html>이 실행되고

 

3처럼 <html> 영역을 누르면 <html>만 실행된다는 것이다.

 

 

 

어디를 클릭했을 때 어떤 것들이 실행되는지 알았으니

 

이제 실행 순서를 알아보자.

 

위 그림의 1번처럼 클릭을 했다고 가정하면,

 

실행 결과는 아래 그림과 같다.

 

  1. 최상위 태그인 html 태그부터 클릭된 위치에 존재하는 최하위 태그까지 이벤트가 전달되고

  2. 최하위 태그부터 이벤트가 실행되며

  3. 다시 최상위 태그인 html 태그까지 이벤트가 전달된다.

 

이때

 

1번을 Capture phase ( event capturing )

 

2번을 Target phase

 

3번을 Bubble phase ( event bubbling )

 

라고 부른다.

 

 

실행 결과는 아래와 같다.

 

"DIV"

"BODY"

"HTML"

 

기본 이벤트 실행 시기가 bubble phase이기 때문에 역순으로 결과가 나타나게 되는데,

 

capture phase일 때 실행되도록 변경할 수도 있다.

 

예를 들어,

 

body의 이벤트를 capture phase일 때 실행되게 변경하면 결과는 아래와 같다.

 

"BODY"

"DIV"

"HTML"

 

<html>, <body>, <div> 모두 capture phase일 때 실행되게 만들면 결과는 아래와 같다.

 

"HTML"

"BODY"

"DIV"

 

 

 

 

 

"문제"

 

 

내가 겪은 문제의 React 코드는 아래와 같았다.

 

<form onSubmit={onSubmit}>
    <TitleDiv>
        <PageButton onClick={handleClick}>
            다른 페이지로 이동
        </PageButton>
    </TitleDiv>

    <RowDiv>
        <Input/>
        <SearchButton type="submit">검색</SearchButton>
    </RowDiv>
    
</form>

 

 

해당 코드의 문제는 input에 값을 넣고 검색을 위해 Enter를 누르면

 

엉뚱하게 PageButton의 onClick이 호출되어 페이지가 이동되는 것이었다.

 

버블링 때문인가 하여 공부를 해보았지만,

 

버블링은 해당 위치에 겹친 태그들에 한해서 일어나는 일이라 위 상황을 설명할 수 없었다.

 

( input에서 Enter를 누르면 input 태그가 이벤트를 받아야 하는데, 갑자기 영 다른 곳에 있는 PageButton이 이벤트를 전달받음 ) 

 

Form 태그 안에서 Enter키 동작은 조금 다른 일이 일어나는 것 같았다.

 

 

 

우선 위 코드와 같이 PageButton이 form 태그 바로 밑에 있는 경우

 

PageButton의 onClick이 호출되어 페이지가 넘어가지만,

 

아래 코드와 같이 PageButton이 SearchButton보다 밑에 있는 경우

 

검색만 되고 PageButton의 onClick은 호출되지 않는다.

 

<form onSubmit={onSubmit}>
    <RowDiv>
        <Input/>
        <SearchButton type="submit">검색</SearchButton>
    </RowDiv>
    
    <TitleDiv>
        <PageButton onClick={handleClick}>
            다른 페이지로 이동
        </PageButton>
    </TitleDiv>
</form>

 

이를 보았을 때, form 태그 안에서 Enter키를 누르면

 

브라우저는 최상위 태그인 html 태그부터

 

1. form 태그와 가장 가깝고

 

2. type="submit"인 버튼까지

 

캡처링을 진행하고, 다시 해당 버튼부터 최상위 태그까지 버블링을 진행하는 듯했다.

 

 

 

문제는 form 태그 가까이 있는 PageButton의 type이 submit이라

 

브라우저가 PageButton을 호출하여 생긴 것이므로

 

PageButton의 type을 button으로 변경하여 해결하였다. 

 

( 이렇게 하면 가장 가깝고 type이 submit인 버튼은 SearchButton이 되니까 )

 

<form onSubmit={onSubmit}>
    <TitleDiv>
        <PageButton onClick={handleClick} type="button">
            다른 페이지로 이동
        </PageButton>
    </TitleDiv>
    
    <RowDiv>
        <Input/>
        <SearchButton type="submit">검색</SearchButton>
    </RowDiv>
    
</form>

 

 

 

 

 

"정리"

 

 

캡처링이란 이벤트가 발생했을 때 최상위 태그인 html 태그부터 클릭된 위치에 존재하는 최하위 태그까지 이벤트가 전달되는 것을 뜻하고

 

버블링이란 캡처링과 정반대로 최하위 태그부터 최상위 태그인 html 태그까지 이벤트가 전달되는 것을 뜻한다. 

 

form 태그 안의 input에서 Enter를 누르면 브라우저는 최상위 태그인 html 태그부터 form 태그와 가장 가까이에 있고 type이 submit인 버튼까지 capturing을 진행하고 다시 해당 버튼부터 최상위 태그까지 bubbling을 실행한다.

 

 

 

 

 


https://www.youtube.com/watch?v=7gKtNC3b_S8