React 공식문서 이해하기 (9)

Syoee·2023년 11월 17일
0

React

목록 보기
9/30
post-thumbnail

Chapter 2. Adding Interactivity

#1 이벤트에 응답하기

학습 목차

1. 이벤트 핸들러 추가하기
2. 이벤트 전파
3. 이벤트 핸들러에 부작용이 생길 수 있을까?


1. 이벤트 핸들러 추가하기

  • 이벤트 핸들러를 추가하려면 먼저 함수를 정의한 다음 이를 적절한 JSX 태그에 prop으로 전달한다.
// 예시
export default function Button() {
  return (
    <button>
      I don't do anything
    </button>
  );
}
  1. Button컴포넌트 안에 handleClick이라는 함수를 선언한다.
  2. 해당 함수 내부의 로직을 구현한다(alert을 사용하여 메시지 표시).
  3. JSX의 <button>onClick={handleClick}를 추가한다.
export default function Button() {
  function handleClick() {
    alert('You clicked me!');
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}
  • handleClick 함수를 정의한 다음 이를 <button>에 prop으로 전달했다.
    (handleClick은 이벤트 핸들러이다.)

    • 이벤트 핸들러 함수는 일반적으로 컴포넌트 안에 정의된다.
    • 이벤트 핸들러 함수는 handle로 시작하는 이름 뒤에 이벤트 이름이 오도록 한다.
  • 관례상 이벤트 핸들러의 이름은 handle 뒤에 이벤트 이름을 붙이는 것이 일반적이다.
    흔히 onClick={handleClick}, onMouseEnter={handleMouseEnter}등을 볼 수 있다.

  • 또는 JSX에서 인라인으로 이벤트 핸들러를 정의할 수도 있다.

// 예시
<button onClick={function handleClick() {
  alert('You clicked me!');
}}>
// 예시

<button onClick={() => {
  alert('You clicked me!');
}}>
  • 이 모든 스타일은 동일히다. 인라인 이벤트 핸들러는 함수가 짧을 경우 편리하다.

주의

  • 이벤트 핸들러에 전달되는 함수는 호출하는 게 아니라 전달되어야 한다.
    • 함수 전달 (올바름)
      <button onClick={handleClick}>
    • 함수 호출 (잘못됨)
      <button onClick={handleClick()}>

  • 차이점은 미세하다.
    • 함수 전달에서는 handleClick 함수가 onClick 이벤트 핸들러로 전달된다.
      이렇게 하면 React가 이를 기억하고 사용자가 버튼을 클릭할 때만 함수를 호출하도록 지시한다.
    • 함수 호출에서 handleClick()끝에 있는 ()은 클릭 없이 렌더링 중에 즉시 함수를 실행한다.
      이는 JSX의 { 및 } 내부의 JavaScript가 바로 실행되기 때문이다.

  • 인라인 코드 작성 시에도 조심해야한다.
    • 함수 전달 (올바름)
      <button onClick={() => alert('...')}>
    • 함수 호출 (잘못됨)
      <button onClick={alert('...')}>

  • 이와 같은 인라인 코드를 전달하면 클릭시 실행되지 않고, 컴포넌트가 렌더링될 때마다 실행된다.
    • <button onClick={alert('You clicked me!')}>
  • 이벤트 핸들러를 인라인으로 정의하려면 다음과 같이 익명 함수로 감싸야한다.
    • <button onClick={() => alert('You clicked me!')}>
  • 렌더링할 때마다 내부에서 코드를 실행하는 대신 나중에 호출할 함수를 생성한다.
    <button onClick={handleClick}>handleClick함수를 전달한다.
    <button onClick={() => alert('...')}>() => alert('...')함수를 전달한다.


    화살표 함수 더 알아보기

1-1. 이벤트 핸들러를 props로 전달하기

  • 가끔 부모 컴포넌트가 자식의 이벤트 핸들러를 지정해야 할 때가 있다.
    Button 컴포넌트를 사용하는 위치에 따라 버튼은 동영상을 재생하고 다른 버튼은 이미지를 업로드하는 등 서로 다른 기능을 실행할 떼가 있다.
  • 디자인 시스템을 사용하는 경우, 버튼 같은 컴포넌트에 스타일링은 포함하지만 동작을 지정하지 않는 것이 일반적이다.

1-2. 이벤트 핸들러 props 이름 정하기

  • <button><div>와 같은 기본 제공 컴포넌트는 onClick과 같은 브라우저 이벤트 이름만 지원한다.
    하지만 자체 컴포넌트를 빌드할 때는 이벤트 핸들러 prop의 이름을 원하는 방식으로 지정할 수 있다.
  • 관례상 이벤트 핸들러 props은 on으로 시작하고 그 뒤에 대문자가 와야 합니다.

KeyNote

  • 이벤트 핸들러에 적절한 HTML 태그를 사용해야 한다.
    예를 들어 클릭을 처리하려면 <div onClick={handleClick}> 대신 <button onClick={handleClick}>을 사용하라.
  • 실제 브라우저의 <button>을 사용하면 키보드 탐색과 같은 기본 브라우저 동작을 사용할 수 있다.
  • 버튼의 기본 브라우저 스타일이 마음에 들지 않고 링크나 다른 UI 요소처럼 보이길 원한다면, CSS를 사용하여 원하는 방식으로 조정할 수 있다.


    접근성 마크업 작성에 대해 자세히 알아보기

2. 이벤트 전파

  • 이벤트 핸들러는 컴포넌트에 있을 수 있는 모든 하위 컴포넌트의 이벤트도 포착합니다. 이벤트가 트리 위로 ‘버블’ 또는 ‘전파’되는 것을 이벤트가 발생한 곳에서 시작하여 트리 위로 올라간다고 합니다.
  • 아래 <div>는 2개의 버튼을 포함한다.
    <div>와 각 버튼에는 모두 고유한 onClick핸들러가 있다.
    버튼을 클릭하면 어떤 핸들러가 실행될까?
// 예시

export default function Toolbar() {
  return (
    <div className="Toolbar" onClick={() => {
      alert('You clicked on the toolbar!');
    }}>
      <button onClick={() => alert('Playing!')}>
        Play Movie
      </button>
      <button onClick={() => alert('Uploading!')}>
        Upload Image
      </button>
    </div>
  );
}
  • 두 버튼 중 하나를 클릭하면 해당 버튼의 onClick이 먼저 실행되고 그 다음에 부모 <div>onClick이 실행된다.
    툴바 자체를 클릭하면 부모 <div>onClick만 실행된다.

주의

  • 첨부한 JSX 태그에서만 작동하는 onScroll을 제외한 모든 이벤트는 React에서 전파된다.

2-1. 전파 중지하기

  • 이벤트 핸들러는 이벤트 객체를 유일한 인수로 받는다.
    이것은 관례상 “event”를 의미하는 e라고 불립니다.
    이 객체를 사용하여 이벤트에 대한 정보를 읽을 수 있습니다.

  • 해당 이벤트 객체를 사용하면 전파를 중지할 수도 있습니다.
    이벤트가 상위 컴포넌트에 도달하지 못하도록 하려면 아래 Button 컴포넌트처럼 e.stopPropagation()을 호출해야 한다.

function Button({ onClick, children }) {
  return (
    <button onClick={e => {
      e.stopPropagation();
      onClick();
    }}>
      {children}
    </button>
  );
}

export default function Toolbar() {
  return (
    <div className="Toolbar" onClick={() => {
      alert('You clicked on the toolbar!');
    }}>
      <Button onClick={() => alert('Playing!')}>
        Play Movie
      </Button>
      <Button onClick={() => alert('Uploading!')}>
        Upload Image
      </Button>
    </div>
  );
}
  1. React는 <button>에 전달된 onClick 핸들러를 호출한다.
  2. Button에 정의된 이 핸들러는 다음을 수행한다.
  • 이벤트가 더 이상 버블링되지 않도록 e.stopPropagation()을 호출한다.
  • Toolbar 컴포넌트에서 전달된 props인 onClick함수를 호출한다.
  1. Toolbar 컴포넌트에 정의된 이 함수는 버튼 자체의 경고를 표시한다.
  2. 전파가 중지되었으므로 부모 <div>onClick 핸들러가 실행되지 않는다.
  • e.stopPropagation() 덕분에 이제 버튼을 클릭하면 두 개의 알림(<button>과 부모 툴바 <div>)이 아닌 하나의 알림(<button>에서)만 표시된다.
    버튼을 클릭하는 것과 주변 툴바를 클릭하는 것은 다르므로 이 UI에서는 전파를 중지하는 것이 적절하다.

2-2. 전파의 대안으로 핸들러 전달하기

  • 아래 클릭 핸들러가 코드 한 줄을 실행한 다음 부모가 전달한 onClick prop을 호출하는 방식을 주목하자.
function Button({ onClick, children }) {
  return (
    <button onClick={e => {
      e.stopPropagation();
      onClick();
    }}>
      {children}
    </button>
  );
}
  • 부모 onClick 이벤트 핸들러를 호출하기 전에 이 핸들러에 코드를 더 추가할 수도 있다.
    이 패턴은 전파에 대한 대안을 제공한다.
    자식 컴포넌트가 이벤트를 처리하는 동시에 부모 컴포넌트가 몇 가지 추가 동작을 지정할 수 있게 해준다.
    프로퍼게이션과 달리 자동이 아니다.
    하지만 이 패턴의 장점은 특정 이벤트의 결과로 실행되는 전체 체인 코드를 명확하게 따라갈 수 있다는 것이다.
  • 전파에 의존하고 있고 어떤 핸들러가 실행되고 왜 실행되는지 추적하기 어려운 경우 대신 이 접근 방식을 시도해 보자.

3. 이벤트 핸들러에 부작용이 생길 수 있을까?

  • 이벤트 핸들러는 부작용이 가장 많이 발생하는 곳이다.
  • 렌더링 함수와 달리 이벤트 핸들러는 순수할 필요가 없으므로 타이핑에 대한 응답으로 input 값을 변경하거나 버튼 누름에 대한 응답으로 목록을 변경하는 등 무언가를 변경하기에 좋은 곳이다.
  • 하지만 일부 정보를 변경하려면 먼저 정보를 저장할 방법이 필요하다.
    React에서는 컴포넌트의 메모리인 state를 사용해 이 작업을 수행한다.

요약

  • <button>과 같은 요소에 함수를 prop으로 전달하여 이벤트를 처리할 수 있다.
  • 이벤트 핸들러는 호출이 아니라 전달해야 한다.
    onClick={handleClick()}이 아니라 onClick={handleClick}이다.
  • 이벤트 핸들러 함수를 개별적으로 또는 인라인으로 정의할 수 있다.
  • 이벤트 핸들러는 컴포넌트 내부에 정의되므로 props에 액세스할 수 있다.
  • 부모에서 이벤트 핸들러를 선언하고 이를 자식에게 prop으로 전달할 수 있다.
  • 이름을 지정하여 이벤트 핸들러 prop을 직접 정의할 수 있다.
  • 이벤트는 위쪽으로 전파됩니다. 이를 방지하려면 첫 번째 인수에 e.stopPropagation()을 호출하라.
  • 이벤트에 원치 않는 기본 브라우저 동작이 있을 수 있다.
    이를 방지하려면 e.preventDefault()를 호출하자.
  • 자식 핸들러에서 이벤트 핸들러 prop을 명시적으로 호출하는 것은 전파에 대한 좋은 대안이다.

React 공식 문서

https://react.dev/

React 비공식 번역 문서

https://react-ko.dev/

MDN

https://developer.mozilla.org/ko/

Wikipedia

https://ko.wikipedia.org/wiki/

profile
함께 일하고 싶어지는 동료, 프론트엔드 개발자입니다.

0개의 댓글

관련 채용 정보