All'alba vincerò

At dawn, I will win!

React

[React] 이벤트 핸들러

나디아 Nadia 2024. 8. 3. 19:46

📌 이벤트(사용자 액션) 처리하기

  • 사용자 액션(행동) → UI 업데이트

 

 

✅ 컴포넌트 영역(순수)와 이벤트 영역(부수)

 

⏩ 컴포넌트 함수 영역

  • 사용자가 행동하지 않아도 진행되는 부분
  • 렌더링 시점에 함수가 실행이 되는 부분
    👉 순수 함수 사용

⏩ 이벤트 핸들러 함수 영역

  • 사용자가 행동을 취해야 진행되는 부분
  • 사이드 이펙트(부수 효과)를 위한 최고의 위치
  • 렌더링 시점에 함수가 실행되지 않는 부분
    👉 사이트 이펙트(부수효과) 함수 사용

 

 

ex) 프로필 목록 컴포넌트

  • 서버에 데이터를 요청해 응답 받아 데이터를 가져와야 한다면 "부수 효과" 
  • 응답 받은 데이터를 기반으로 리스트 렌더링 하는 것은 "순수 함수"

 

 

📢 컴포넌트 함수 내부의 이벤트 핸들러 함수에서 부수효과를 다루는 이유

 

👉 렌더링 될 때 이벤트 핸들러 함수가 자동으로 실행되는 것이 아니고, 사용자가 행동을 하여 이벤트가 발생할 때에 비로소 이벤트 핸들러 함수가 실행되므로 컴포넌트 영역은 순수하다 

  • 컴포넌트 함수 내부에 이벤트 핸들러 함수가 존재하더라도, 컴포넌트의 출력 값인 JSX 마크업 생성에 영향을 주지 않기 때문에  '같은 입력 👉 같은 출력' 이라는 순수 함수의 조건을 만족
  • 컴포넌트 함수가 실행되는 동안(렌더링하는 동안) 외부의 상태를 변경하지 않는다는 조건도 만족

 

 

 

✅ 이벤트 핸들러 추가

  • 함수를 정의하고 JSX 태그에 prop 형태로 전달
  • 이벤트 핸들러 함수명은 handle로 시작한다.
    (ex. onClick={handleClick}, onMouseEnter={handleMouseEnter})

 

⏩ 이벤트 핸들러

  • 컴포넌트 내부(바디(return 위에))에 정의
  1. 컴포넌트 내부에 이벤트 핸들러 함수 정의
  2. JSX의 태그 prop으로 이벤트 핸들러 추가
  // 1. 컴포넌트 바디(함수 몸체) 내부
  // 이벤트 핸들러 정의
  const handleClickFirstLink = (e) => {
    e.preventDefault();

    const firstLink = document.querySelector('[href="#jsx-markup"]');
    firstLink.dataset.element = 'jsx-markup';
  };
  
  
  // 사이드 이펙트(부수 효과) 처리 함수
  const handleClickLastLink = (e) => {
    e.preventDefault();

    const lasatLink = document.querySelector('[href="#responding-to-events"]');
    lasatLink.dataset.element = 'responding-to-events';
  };


  // 2. JSX 내부
  return (
    <nav className="NavContents" aria-label="학습 주제 탐색">
      <a
        href="#jsx-markup"
        onClick={handleClickFirstLink} // DOM 월드에서 사용자에 의해 실행
      >
        JSX 마크업
      </a>

      <a
        href="#responding-to-events"
        className="active"
        onClick={handleClickLastLink}
      >
        이벤트 응답
      </a>
    </nav>
  );

 

 

 

⏩ 인라인 핸들러

  • JSX 내부에 정의
  • 짧은 함수들을 정의할 때 편리
<button onClick={function handleClick() {
  alert('You clicked me!');
}}>


 

 

 

✅ 이벤트 핸들러에서 props 읽기

  • 이벤트 핸들러는 컴포넌트 내부에서 선언되기에 해당 컴포넌트의 prop에 접근할 수 있다.

 

1. 상위 컴포넌트에서 이벤트 핸들러를 prop으로 전달하기

function RespondingToEvents() {
  // 함수 지역 변수 (데이터)
  let message = '김사부! "집중~~"';

  // 함수 내부의 지역 함수 (데이터)
  const printMessage = () => console.log(message);

  const updateMessage = (addMessage) => {
    message += addMessage;
  };

  return (
    <div className="ViewRespondingToEvent">
      <!-- 컴포넌트 내부의 함수를 prop으로 전달 -->
      <EventHandlerProp onPrintMessage={updateMessage} />
    </div>
  );
}

 

 

2. 하위 컴포넌트에서 이벤트 핸들러를 prop으로 받아오기

// 하위 컴포넌트
// 상위 컴포넌트에서 전달한 함수를 prop으로 받아옴
function EventHandlerProp({ onPrintMessage }) {

  const handleEnter = () => {
    console.log('enter');
    onPrintMessage?.(' ⭐️'); // '김사부! 집중~~ ⭐️'
  };

  const handleLeave = () => {
    console.log('leave')
  };

  return (
    <details>
      <summary onPointerEnter={handleEnter} onPointerLeave={handleLeave}>
        <b>이벤트 핸들러 추가하기</b>
      </summary>
      <p>
        이벤트 핸들러 추가를 위해서는 먼저 함수를 정의하고,
        이를 적절한 JSX 요소에 prop으로 전달해야 합니다.
      </p>
    </details>
  );
}

export default EventHandlerProp;

 

 

 

 

✅ 이벤트 전파(Event Propagation)

: 이벤트가 발생했을 때 이벤트가 DOM 트리에서 어떻게 전달되는지를 설명하는 과정

  • 버블링(Bubbling) 
  • 캡쳐(Capturing)
import LayoutBox from './LayoutBox';

function EventPropagation() {

  function returnHandlePrint(color) {
    return function handlePrint(e) {
      console.log(color, e.target);
    };
  }

  return (
    <details>
      <LayoutBox style={styles.cyan} onClick={returnHandlePrint('cyan')}>
        <LayoutBox
          style={styles.magenta}
          onClick={returnHandlePrint('magenta')}
        >
          <LayoutBox
            style={styles.yellow}
            onClick={returnHandlePrint('yellow')}
          >
            <LayoutBox
              style={styles.purple}
              onClick={returnHandlePrint('purple')}
            />
          </LayoutBox>
        </LayoutBox>
      </LayoutBox>
    </details>
  );
}

const styles = {
  cyan: {
    '--color': 'var(--cyan)',
  },
  magenta: {
    '--color': 'var(--magenta)',
  },
  yellow: {
    '--color': 'var(--yellow)',
  },
  purple: {
    '--color': 'var(--purple, #7423f6)',
  },
};

export default EventPropagation;

 

 

 

⏩ 이벤트 위임(Event Delegation)

: 이벤트 전파의 개념을 활용하여 부모 요소에서 자식 요소의 이벤트를 처리하는 방법

  • 자식 요소 각각에 이벤트 리스너를 추가하는 대신, 부모 요소에 이벤트 리스너를 추가하여 자식 요소에서 발생한 이벤트를 처리

 

 

⏩ 이벤트 전파 중지

event.stopPropagaion()
  • 이벤트 핸들러가 상위 태그로 버블링되지 않도록 막는다.
    (해당 이벤트에만 실행)

 

 

⏩ 전파 대안으로 핸들러 전달

  • 부모 컴포넌트가추가적인 동작하게 하여 자식 컴포넌트가 이벤트를 처리할 수 있도록 한다.
  • 전파와는 다르게 자동으로 동작하지 않는다.

 

 

⏩ 기본 작동 방지

event.preventDefault()
  • 기본 브라우저 동작을 막는다.

 


 

 

이벤트에 응답하기 – React

The library for web and native user interfaces

ko.react.dev