react.js

react 공식문서 학습 - Responding to Events

tues 2023. 11. 29. 22:23

이벤트에 응답하기

 

🎈 이벤트 핸들러 추가하기

이벤트 핸들러를 추가하려면 먼저 함수를 정의한 다음 이를 적절한 JSX 태그에 prop으로 전달합니다. 

 

올바른 함수 전달 ⭕

<button onClick={handleClick}>

handleClick 함수가 onClick 이벤트 핸들러로 전달됩니다. 이렇게 하면 react가 이를 기억하고 사용자가 버튼을 클릭할 때만 함수를 호출하도록 지시합니다. 

 

잘못된 함수 호출 ❌

<button onClick={handleClick()}>

handleClick()끝에 있는 ()은 클릭없이 렌더링 중에 즉시 함수를 실행합니다. 이는 JSX의 내부의 javascript가 바로 실행되기 때문입니다. 

 

올바른 함수 전달 ⭕

<button onClick={() => alert('...')}>

이와 같이 인라인 코드를 전달하면 클릭시 실행되지 않고 컴포넌트가 렌더링될 때마다 실행됩니다.

이벤트 핸들러를 인라인으로 정의하려면 익명 함수로 감싸주세요 

렌더링할 때마다 내부에서 코드를 실행하는 대신 나중에 로출할 함수를 생성합니다.

 

잘못된 함수 호출 ❌

<button onClick={alert('...')}>

 

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

이벤트 핸들러는 컴포넌트 내부에서 선언되기 때문에 컴포넌트의 props에 접근할 수 있습니다. 다음은 클릭하면 message prop과 함께 alert을 표시하는 버튼입니다.

function AlertButton({ message, children }) {
  return (
    <button onClick={() => alert(message)}>
      {children}
    </button>
  );
}

export default function Toolbar() {
  return (
    <div>
      <AlertButton message="Playing!">
        Play Movie
      </AlertButton>
      <AlertButton message="Uploading!">
        Upload Image
      </AlertButton>
    </div>
  );
}

 

🎈 이벤트 핸들러를 props로 전달하기

가끔 부모 컴포넌트가 자식의 이벤트 핸들러를 지정하고 싶을 때가 있습니다. Button 컴포넌트를 사용하는 위치에 따라 버튼은 동영상을 재생하고 다른 버튼은 이미지를 업로드하는 등 서로 다른 기능을 실행하고 싶을 수 있습니다. 

 

컴포넌트가 부모로부터 받는 prop을 이벤트 핸들러로 다음과 같이 전달합니다.

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

function PlayButton({ movieName }) {
  function handlePlayClick() {
    alert(`Playing ${movieName}!`);
  }

  return (
    <Button onClick={handlePlayClick}>
      Play "{movieName}"
    </Button>
  );
}

function UploadButton() {
  return (
    <Button onClick={() => alert('Uploading!')}>
      Upload Image
    </Button>
  );
}

export default function Toolbar() {
  return (
    <div>
      <PlayButton movieName="Kiki's Delivery Service" />
      <UploadButton />
    </div>
  );
}

 

여기서 Toolbar 컴포넌트는 playButton과 UploadButton을 렌더링합니다.

PlayButton은 handlePlayClick을 onClick prop으로 내부의 Button에 전달합니다.

마지막으로 Button 컴포넌트는 onClick이라는 prop을 받습니다. 해당 prop을 브라우저의 빌트인 <button>으로 직접 전달하며, onClick={onClick}을 사용합니다. 이는 클릭시 전달된 함수를 호출하도록 react에 지시합니다. 

 

🎈이벤트 핸들러 props 이름 정하기 

<button> 및 <div>와 같은 기본 제공 컴포넌트는 onClick과 같은 브라우저 이벤트 이름만 지원합니다. 하지만 자체 컴포넌트를 빌드할 때는 이벤트 핸들러 prop의 이름을 원하는 방식으로 지정할 수 있습니다. 

관례상 이벤트 핸들러 props는 on으로 시작하고 그 뒤에 대문자가 와야 합니다.

예를 들어, Button 컴포넌트의 onClick prop은 onSmash로 호출할 수 있습니다.

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

export default function App() {
  return (
    <div>
      <Button onSmash={() => alert('Playing!')}>
        Play Movie
      </Button>
      <Button onSmash={() => alert('Uploading!')}>
        Upload Image
      </Button>
    </div>
  );
}

이 예제에서 <button onClick={onSmash}> 는 브라우저 <button> (소문자)에 여전히 onClick이라는 prop이 필요하지만 사용자 정의 Button컴포넌트가 수신하는 prop이름은 사용자가 지정할 수 있음을 보여줍니다 

 

🎈 이벤트 전파

이벤트 핸들러는 컴포넌트에 있을 수 있는 모든 하위 컴포넌트의 이벤트도 포착합니다. 이벤트가 트리 위로 버블 또는 전파되는 것을 이벤트가 발생한 곳에서 시작하여 트리 위로 올라간다고 합니다.

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이 실행됩니다.

 

🎈 전파 중지하기

이벤트 핸들러는 이벤트 객체를 유일한 인수로 받습니다. 이것은 관례상 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>
  );
}

버튼 클릭 -> react는 onClick 핸들러 호출-> 이벤트가 더이상 버블링되지 않도록 e.stopPropagation()을 호출-> Toolbar 컴포넌트에 전달된 props인 onClick 호출-> 경고 표시 -> 전파 중지

 

<div onClickCapture={() => { /* this runs first | 먼저 실행됨 */ }}>
  <button onClick={e => e.stopPropagation()} />
  <button onClick={e => e.stopPropagation()} />
</div>

드물게 전파 중지를 해도 하위 요소의 모든 이벤트가 포착되는 경우에 쓰임

 

🎈 전파의 대안으로 핸들러 전달하기 

부모가 전달한 onClick prop을 호출하는 방식: 

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

 

부모 onClick 이벤트 핸들러를 호출하기 전에 코드추가- 전파에 대한 대안을 제공합니다. 자식 컴포넌트가 이벤트를 처리하는 동시에 부모 컴포넌트가 몇 가지 추가동작을 지정할 수 있게 해줍니다. 

 

🎈기본 동작 방지

export default function Signup() {
  return (
    <form onSubmit={() => alert('Submitting!')}>
      <input />
      <button>Send</button>
    </form>
  );
}

전체 페이지를 다시 로드함

 

export default function Signup() {
  return (
    <form onSubmit={e => {
      e.preventDefault();
      alert('Submitting!');
    }}>
      <input />
      <button>Send</button>
    </form>
  );
}

e.preventDefault()를 호출하여 이런 일이 발생하지 않도록 함

 

▶️ e.stopPropagation() 은 위 태그에 연결된 이벤트 핸들러의 실행 중지

▶️e.preventDefault()는 해당 이벤트가 있는 몇가지 이벤트에 대해 기본 브라우저 동작 방지

 

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