원치 않는 클릭 이벤트, 메시지 수정 버그 해결[TOY / Simple-SNS]

알락·2022년 11월 25일
0

Simple-SNS

목록 보기
7/9

배경

메시지 디테일 페이지를 만들고 난 이후에 문제가 생겼다. 메시지를 수정할 때 생기는 구역을 눌렀을 때 원치 않는 클릭 이벤트가 발생하는 것이다. 메시지 수정이 거의 불가능할 정도의 큰 버그여서 해결해보기로 했다.


해결 과정

메세지의 내용이 들어가 있는 부분을 누르면 디테일 페이지로 넘어가게 구현됀다. 하지만 그 부분을 래핑하고 있는 Link 컴포넌트가 <a> 태그를 기반으로 만들어져 있기 때문에 원치 않는 곳에서 클릭 이벤트가 발생하는 것이었다.

문제의 코드는 다음과 같다.

[Message.js 문제코드]

// 생략
<Link className="message-body" to={"/detail/"+message._id}>
        {isUpdate ?
            <div>
                <div className="box-update" aria-label="update">
                    <textarea className="cotent-box" 
                        rows="5" 
                        placeholder="내용을 입력해주세요."
                        onChange={changeContentHandler}
                    >
                </textarea>
                </div>
                <div className="update-button-wrapper">
                    <button className="btn-primary mr-2" onClick={deactivateUpdate}>취소</button>
                    <button className="btn-primary" onClick={clickUpdateHandler}>수정</button>
                </div>
            </div>
            :
            <p>
                {content}
            </p>
        }
</Link> {/* Message Body */}
// 생략

원래 원하는 이벤트 발생 조건은 위의 박스가 클릭 됐을 때이다. 하지만 위처럼 update 구역까지 <Link> 컴포넌트로 감싸다 보니 아래의 사진 속 박스에서도 클릭이 돼버린다.

문제는 간단하게 풀린다.

[해결 코드]

<Link className="message-body" to={"/detail/"+message._id}>
        {isUpdate ?
         	{/************ 해결 방법 ***************/}
            <div onClick={(e)=>e.preventDefault();}>
                <div className="box-update" aria-label="update">
                    <textarea className="cotent-box" 
                        rows="5" 
                        placeholder="내용을 입력해주세요."
                        onChange={changeContentHandler}
                    >
                </textarea>
                </div>
                <div className="update-button-wrapper">
                    <button className="btn-primary mr-2" onClick={deactivateUpdate}>취소</button>
                    <button className="btn-primary" onClick={clickUpdateHandler}>수정</button>
                </div>
            </div>
            :
            <p>
                {content}
            </p>
        }
</Link> {/* Message Body */}

업데이트 구역에 해당하는 가장 상위 엘리먼트의 클릭 이벤트 핸들러에서 e.preventDefault(); 명령을 실행해주는 것이다. 이 명령은 기본적으로 브라우저에서 설정되어 있는 이벤트의 발생을 막아버리는 것이다. react-router 라이브러리의 <Link> 컴포넌트가 <a> 태그를 기반으로 하기 때문에 위 명령으로 이 문제를 해결할 수 있었다.

그리고 가장 상위 엘리먼트에 이벤트 핸들러를 할당한 이유는, 자식 엘리먼트에게서 이벤트가 전파되어오기 때문이다. 클릭된 자식 엘리먼트에서 이벤트가 전파되어 <Link>까지 전달이 되면 비로소 해당 이벤트가 발생된다. 하지만 전달되기 바로 이전에 이벤트 발생을 막아버리기 때문에 더 이상 문제가 없게 된다. 만약 내가 <textarea>e.preventDefault() 명령을 수행했다면 메시지 타이핑은 가능하지만 최종적으로 전송 버튼을 누를 수가 없었을 것이다.


알게 된 것

  • e.preventDefault()의 쓰임새
  • 이벤트 propagation의 존재
profile
블록체인 개발 공부 중입니다, 프로그래밍 공부합시다!

3개의 댓글

comment-user-thumbnail
2022년 11월 27일

저도 이벤트 버블링을 흥미롭게 본 경험이 있어서 코드를 찬찬히 살펴봤습니다.

최상위 div에서 e.preventDefault()하는건 버그 해결만을 위해서 행동을 너무 제약하는 것 같다는 생각이 드는데 문제가 발생하는 textarea 태그에서 onClick 이벤트의 콜백을 정의해서event.stop.propagation() 을 호출하는게 낫지 않을까요? 상위로 이벤트가 전달되는 현상이 문제이므로, 상위에서 해결을 하는 것 보다, 해당 버그에 책임이 있는 태그에서 상위로 전달자체가 되지 않게 설계하는게 좋을 것 같다는 개인적인 생각이 듭니다.

왜냐하면 textArea밖의 div를 사용자가 클릭할 경우, 자연스럽게 입력창이 없어지는게 사용자 경험에서 직관적이라 생각하기 때문입니다. 물론 이건 프론트엔드 디자인 취향 차이이긴 하겠지만...

또 다른 이유는 추후 div에 onclick 이벤트를 새롭게 정의해야 할 경우 textarea까지 다시 손봐야하니까 버그의 발생 가능성이 높아지지 않을까 하는 생각입니다. textarea 컴포넌트가 상위 div에 의존적이지 않게되어 하나로서 완전히 기능하는 컴포넌트화 한다면 재사용성이 높아지는 효과도 장점인 것 같아요.

2개의 답글