[React] 자식 요소의 onClick 시 부모 요소의 onClick 도 같이 수행되는 현상

Narcoker·2023년 7월 14일
0

ErrorHandling

목록 보기
12/14

에러 상황

Todo.presenter.js

import React from "react";
import * as S from "./Todo.style";
import { faTrash } from "@fortawesome/free-solid-svg-icons";

function TodoPresenter({
  todo,
  handleRemoveTodo,
  handleChangeTodoState,
  handleSetModeEDIT,
}) {
  return (
    <S.Wrapper $state={todo.state} onClick={() => handleSetModeEDIT(todo.uuid)}>
      <S.ContentsLeft>
        <S.StateCircle
          $state={todo.state}
          onClick={(e) => {
            handleChangeTodoState(e, todo.uuid);
          }}
        />
      </S.ContentsLeft>
      <S.ContentsCenter>
        <S.Title $state={todo.state}>{todo.title}</S.Title>
        <S.DataWrapper>
          <S.Date>시작 일: {todo.startDate}</S.Date>
          <S.Date $right>종료 일: {todo.endDate}</S.Date>
        </S.DataWrapper>
      </S.ContentsCenter>
      <S.ContentsRight>
        <S.StateText>{todo.state}</S.StateText>
        <S.StyledIcon
          icon={faTrash}
          onClick={(e) => {
            handleRemoveTodo(e, todo.uuid); // 클릭 시 handleSetModeEDIT(todo.uuid) 도 수행됨
          }}
        />
      </S.ContentsRight>
    </S.Wrapper>
  );
}

export default TodoPresenter;

Todo.container.js 일부

  const dispatch = useDispatch();
  const handleRemoveTodo = (e, uuid) => {
    dispatch(removeTodo(uuid));
    dispatch(setModeADD());
  };
  const handleChangeTodoState = (e,uuid) => {
    dispatch(changeTodoState(uuid));
  };
  const handleSetModeEDIT = (uuid) => {
    dispatch(setModeEDIT());
    dispatch(setSelectedDetails(uuid));
  };

자식 요소인 S.StyledIcon 요소를 클릭하면 해당 요소의 onClick 이 수행되고
<S.Wrapper $state={todo.state} onClick={() => handleSetModeEDIT(todo.uuid)}>
의 onClick 이 이후에 수행되는 현상이 발생했다.

이유

이벤트 버블링 현상 때문이다.
클릭 같은 이벤트가 발생하면 해당 요소에 바로 이벤트가 발생되는 것이 아니라
DOM Tree 를 따라 들어가면서 해당 요소를 찾아가고 이후 다시 DOM Tree를 탈출한다.

따라들어가는 것을 이벤트 캡처링, 탈출하는 것을 이벤트 버블링이라고 한다.

React에서는 일반적으로 이벤트 캡처링 시 같은 이벤트 존재하더라도 발생하지 않는다.
즉, 이벤트 버블링 시에만 이벤트 핸들링 함수를 동작시킨다.

이러한 이유로 위 현상이 발생했던 것이다.

해결책

이벤트 전파를 막아주는 메서드 event.stopPropagation() 을 사용했다.

Todo.container.js 수정

  const dispatch = useDispatch();
  const handleRemoveTodo = (e, uuid) => {
    e.stopPropagation(); // 추가
    dispatch(removeTodo(uuid));
    dispatch(setModeADD());
  };
  const handleChangeTodoState = (e,uuid) => {
    e.stopPropagation(); // 추가
    dispatch(changeTodoState(uuid));
  };
  const handleSetModeEDIT = (uuid) => {
    dispatch(setModeEDIT());
    dispatch(setSelectedDetails(uuid));
  };
profile
열정, 끈기, 집념의 Frontend Developer

0개의 댓글