React lets you add event handlers to your JSX. Event handlers are your own functions that will be triggered in response to interactions like clicking, hovering, focusing form inputs, and so on. React를 사용하면 JSX에 이벤트 핸들러를 추가할 수 있습니다. 이벤트 핸들러는 click, hover, input의 focus 등과 같은 상호작용에 반응하여 발생하는 자체 함수입니다.
You will learn학습 내용
- Different ways to write an event handler
- How to pass event handling logic from a parent component
- How events propagate and how to stop them
- 이벤트 핸들러를 작성하는 다양한 방법
- 부모 컴포넌트로부터 이벤트 핸들링 로직을 전달하는 방법
- 이벤트가 전파되는 방식과 중지하는 방법
Adding event handlers이벤트 핸들러 추가하기
To add an event handler, you will first define a function and then pass it as a prop to the appropriate JSX tag. For example, here is a button that doesn’t do anything yet: 이벤트 핸들러를 추가하려면 먼저 함수를 정의한 다음 이를 적절한 JSX 태그에 prop으로 전달합니다. 예를 들어, 아직 아무 작업도 수행하지 않는 버튼이 있습니다:
export default function Button() { return ( <button> I don't do anything </button> ); }
You can make it show a message when a user clicks by following these three steps: 다음의 세 단계를 거쳐 사용자가 클릭할 때 메시지를 표시하도록 설정할 수 있습니다:
- Declare a function called
handleClick
inside yourButton
component. - Implement the logic inside that function (use
alert
to show the message). - Add
onClick={handleClick}
to the<button>
JSX.
Button
컴포넌트 안에handleClick
이라는 함수를 선언합니다.- 해당 함수 내부의 로직을 구현합니다(
alert
을 사용하여 메시지 표시). - JSX의
<button>
에onClick={handleClick}
를 추가합니다.
export default function Button() { function handleClick() { alert('You clicked me!'); } return ( <button onClick={handleClick}> Click me </button> ); }
You defined the handleClick
function and then passed it as a prop to <button>
. handleClick
is an event handler. Event handler functions:
handleClick
함수를 정의한 다음 이를 <button>
에 prop으로 전달했습니다. handleClick
은 이벤트 핸들러입니다. 이벤트 핸들러 함수는:
- Are usually defined inside your components.
- Have names that start with
handle
, followed by the name of the event.
- 일반적으로 컴포넌트 안에 정의됩니다.
handle
로 시작하는 이름 뒤에 이벤트 이름이 오도록 합니다.
By convention, it is common to name event handlers as handle
followed by the event name. You’ll often see onClick={handleClick}
, onMouseEnter={handleMouseEnter}
, and so on.
관례상 이벤트 핸들러의 이름은 handle
뒤에 이벤트 이름을 붙이는 것이 일반적입니다. 흔히 onClick={handleClick}
, onMouseEnter={handleMouseEnter}
등을 볼 수 있습니다.
Alternatively, you can define an event handler inline in the JSX: 또는 JSX에서 인라인으로 이벤트 핸들러를 정의할 수도 있습니다:
<button onClick={function handleClick() {
alert('You clicked me!');
}}>
Or, more concisely, using an arrow function: 또는, 더 간결하게 화살표 함수를 사용할 수도 있습니다:
<button onClick={() => {
alert('You clicked me!');
}}>
All of these styles are equivalent. Inline event handlers are convenient for short functions. 이 모든 스타일은 동일합니다. 인라인 이벤트 핸들러는 함수가 짧을 경우 편리합니다.
Reading props in event handlers이벤트 핸들러에서 props 읽기
Because event handlers are declared inside of a component, they have access to the component’s props. Here is a button that, when clicked, shows an alert with its message
prop:
이벤트 핸들러는 컴포넌트 내부에서 선언되기 때문에 컴포넌트의 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> ); }
This lets these two buttons show different messages. Try changing the messages passed to them. 이렇게 하면 이 두 버튼이 서로 다른 메시지를 표시할 수 있습니다. 전달되는 메시지를 변경해 보세요.
Passing event handlers as props이벤트 핸들러를 props로 전달하기
Often you’ll want the parent component to specify a child’s event handler. Consider buttons: depending on where you’re using a Button
component, you might want to execute a different function—perhaps one plays a movie and another uploads an image.
가끔 부모 컴포넌트가 자식의 이벤트 핸들러를 지정하고 싶을 때가 있습니다. Button
컴포넌트를 사용하는 위치에 따라 버튼은 동영상을 재생하고 다른 버튼은 이미지를 업로드하는 등 서로 다른 기능을 실행하고 싶을 수 있습니다.
To do this, pass a prop the component receives from its parent as the event handler like so: 이렇게 하기 위해서는, 컴포넌트가 부모로부터 받는 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> ); }
Here, the Toolbar
component renders a PlayButton
and an UploadButton
:
여기서 Toolbar
컴포넌트는 PlayButton
과 UploadButton
을 렌더링합니다:
PlayButton
passeshandlePlayClick
as theonClick
prop to theButton
inside.UploadButton
passes() => alert('Uploading!')
as theonClick
prop to theButton
inside.
PlayButton
은handlePlayClick
을onClick
prop으로 내부의Button
에 전달합니다.UploadButton
은() => alert('Uploading!')
를onClick
prop으로 내부의Button
에 전달합니다.
Finally, your Button
component accepts a prop called onClick
. It passes that prop directly to the built-in browser <button>
with onClick={onClick}
. This tells React to call the passed function on click.
마지막으로 Button
컴포넌트는 onClick
이라는 prop을 받습니다. 해당 prop을 브라우저의 빌트인 <button>
으로 직접 전달하며, onClick={onClick}
을 사용합니다. 이는 클릭 시 전달된 함수를 호출하도록 React에 지시합니다.
If you use a design system, it’s common for components like buttons to contain styling but not specify behavior. Instead, components like PlayButton
and UploadButton
will pass event handlers down.
디자인 시스템을 사용하는 경우, 버튼 같은 컴포넌트에 스타일링은 포함하지만 동작을 지정하지 않는 것이 일반적입니다. 대신 PlayButton
및 UploadButton
과 같은 컴포넌트는 이벤트 핸들러를 전달합니다.
Naming event handler props이벤트 핸들러 props 이름 정하기
Built-in components like <button>
and <div>
only support browser event names like onClick
. However, when you’re building your own components, you can name their event handler props any way that you like.
<button>
및 <div>
와 같은 기본 제공 컴포넌트는 onClick
과 같은 브라우저 이벤트 이름만 지원합니다. 하지만 자체 컴포넌트를 빌드할 때는 이벤트 핸들러 prop의 이름을 원하는 방식으로 지정할 수 있습니다.
By convention, event handler props should start with on
, followed by a capital letter.
관례상 이벤트 핸들러 props은 on
으로 시작하고 그 뒤에 대문자가 와야 합니다.
For example, the Button
component’s onClick
prop could have been called onSmash
:
예를 들어, 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> ); }
In this example, <button onClick={onSmash}>
shows that the browser <button>
(lowercase) still needs a prop called onClick
, but the prop name received by your custom Button
component is up to you!
이 예제에서 <button onClick={onSmash}>
는 브라우저 <button>
(소문자)에 여전히 onClick
이라는 prop이 필요하지만 사용자 정의 Button
컴포넌트가 수신하는 prop 이름은 사용자가 지정할 수 있음을 보여줍니다!
When your component supports multiple interactions, you might name event handler props for app-specific concepts. For example, this Toolbar
component receives onPlayMovie
and onUploadImage
event handlers:
컴포넌트가 여러 상호작용을 지원하는 경우, 앱별 개념에 따라 이벤트 핸들러 props의 이름을 지정할 수 있습니다. 예를 들어, 이 Toolbar
컴포넌트는 onPlayMovie
및 onUploadImage
이벤트 핸들러를 수신합니다:
export default function App() { return ( <Toolbar onPlayMovie={() => alert('Playing!')} onUploadImage={() => alert('Uploading!')} /> ); } function Toolbar({ onPlayMovie, onUploadImage }) { return ( <div> <Button onClick={onPlayMovie}> Play Movie </Button> <Button onClick={onUploadImage}> Upload Image </Button> </div> ); } function Button({ onClick, children }) { return ( <button onClick={onClick}> {children} </button> ); }
Notice how the App
component does not need to know what Toolbar
will do with onPlayMovie
or onUploadImage
. That’s an implementation detail of the Toolbar
. Here, Toolbar
passes them down as onClick
handlers to its Button
s, but it could later also trigger them on a keyboard shortcut. Naming props after app-specific interactions like onPlayMovie
gives you the flexibility to change how they’re used later.
App
컴포넌트는 Toolbar
가 onPlayMovie
또는 onUploadImage
로 어떤 작업을 수행할지 알 필요가 없다는 점을 주목하세요. 이것이 Toolbar
의 구현 세부 사항입니다. 여기서 Toolbar
는 Button
에 onClick
핸들러로 전달하지만 나중에 키보드 단축키에서 촉발시킬 수도 있습니다. props의 이름을 onPlayMovie
와 같은, 앱별 상호작용의 이름을 따서 지정하면 나중에 사용 방식을 유연하게 변경할 수 있습니다.
Event propagation이벤트 전파
Event handlers will also catch events from any children your component might have. We say that an event “bubbles” or “propagates” up the tree: it starts with where the event happened, and then goes up the tree. 이벤트 핸들러는 컴포넌트에 있을 수 있는 모든 하위 컴포넌트의 이벤트도 포착합니다. 이벤트가 트리 위로 ‘버블’ 또는 ‘전파’되는 것을 이벤트가 발생한 곳에서 시작하여 트리 위로 올라간다고 합니다.
This <div>
contains two buttons. Both the <div>
and each button have their own onClick
handlers. Which handlers do you think will fire when you click a button?
이 <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> ); }
If you click on either button, its onClick
will run first, followed by the parent <div>
’s onClick
. So two messages will appear. If you click the toolbar itself, only the parent <div>
’s onClick
will run.
두 버튼 중 하나를 클릭하면 해당 버튼의 onClick
이 먼저 실행되고 그다음에 부모 <div>
의 onClick
이 실행됩니다. 따라서 두 개의 메시지가 나타납니다. 툴바 자체를 클릭하면 부모 <div>
의 onClick
만 실행됩니다.
Stopping propagation전파 중지하기
Event handlers receive an event object as their only argument. By convention, it’s usually called e
, which stands for “event”. You can use this object to read information about the event.
이벤트 핸들러는 이벤트 객체를 유일한 인수로 받습니다. 이것은 관례상 “event”를 의미하는 e
라고 불립니다. 이 객체를 사용하여 이벤트에 대한 정보를 읽을 수 있습니다.
That event object also lets you stop the propagation. If you want to prevent an event from reaching parent components, you need to call e.stopPropagation()
like this Button
component does:
해당 이벤트 객체를 사용하면 전파를 중지할 수도 있습니다. 이벤트가 상위 컴포넌트에 도달하지 못하도록 하려면 아래 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> ); }
When you click on a button: 버튼을 클릭하면:
- React calls the
onClick
handler passed to<button>
. - That handler, defined in
Button
, does the following:- Calls
e.stopPropagation()
, preventing the event from bubbling further. - Calls the
onClick
function, which is a prop passed from theToolbar
component.
- Calls
- That function, defined in the
Toolbar
component, displays the button’s own alert. - Since the propagation was stopped, the parent
<div>
’sonClick
handler does not run.
- React는
<button>
에 전달된onClick
핸들러를 호출합니다. Button
에 정의된 이 핸들러는 다음을 수행합니다:- 이벤트가 더 이상 버블링되지 않도록
e.stopPropagation()
을 호출합니다. Toolbar
컴포넌트에서 전달된 props인onClick
함수를 호출합니다.
- 이벤트가 더 이상 버블링되지 않도록
Toolbar
컴포넌트에 정의된 이 함수는 버튼 자체의 경고를 표시합니다.- 전파가 중지되었으므로 부모
<div>
의onClick
핸들러가 실행되지 않습니다.
As a result of e.stopPropagation()
, clicking on the buttons now only shows a single alert (from the <button>
) rather than the two of them (from the <button>
and the parent toolbar <div>
). Clicking a button is not the same thing as clicking the surrounding toolbar, so stopping the propagation makes sense for this UI.
e.stopPropagation()
덕분에 이제 버튼을 클릭하면 두 개의 알림(<button>
과 부모 툴바 <div>
)이 아닌 하나의 알림(<button>
에서)만 표시됩니다. 버튼을 클릭하는 것과 주변 툴바를 클릭하는 것은 다르므로 이 UI에서는 전파를 중지하는 것이 적절합니다.
Deep Dive | 심층 탐구
In rare cases, you might need to catch all events on child elements, even if they stopped propagation. For example, maybe you want to log every click to analytics, regardless of the propagation logic. You can do this by adding Capture
at the end of the event name:
드물지만 하위 요소에서 전파가 중지된 경우에도 하위 요소의 모든 이벤트를 포착해야 하는 경우가 있습니다. 예를 들어, 전파 로직에 관계없이 모든 클릭을 분석도구에 기록하고자 할 수 있습니다. 이벤트 이름 끝에 Capture
를 추가하면 이 작업을 수행할 수 있습니다:
<div onClickCapture={() => { /* this runs first | 먼저 실행됨 */ }}>
<button onClick={e => e.stopPropagation()} />
<button onClick={e => e.stopPropagation()} />
</div>
Each event propagates in three phases: 각 이벤트는 세 단계로 전파됩니다:
- It travels down, calling all
onClickCapture
handlers. - It runs the clicked element’s
onClick
handler. - It travels upwards, calling all
onClick
handlers.
- 아래로 이동하면서 모든
onClickCapture
핸들러를 호출합니다. - 클릭한 요소의
onClick
핸들러를 실행합니다. - 상위로 이동하면서 모든
onClick
핸들러를 호출합니다.
Capture events are useful for code like routers or analytics, but you probably won’t use them in app code. 캡처 이벤트는 라우터나 분석과 같은 코드에는 유용하지만, 앱 코드에는 잘 사용하지 않을 것입니다.
Passing handlers as alternative to propagation전파의 대안으로 핸들러 전달하기
Notice how this click handler runs a line of code and then calls the onClick
prop passed by the parent:
이 클릭 핸들러가 코드 한 줄을 실행한 다음 부모가 전달한 onClick
prop을 호출하는 방식을 주목하세요:
function Button({ onClick, children }) {
return (
<button onClick={e => {
e.stopPropagation();
onClick();
}}>
{children}
</button>
);
}
You could add more code to this handler before calling the parent onClick
event handler, too. This pattern provides an alternative to propagation. It lets the child component handle the event, while also letting the parent component specify some additional behavior. Unlike propagation, it’s not automatic. But the benefit of this pattern is that you can clearly follow the whole chain of code that executes as a result of some event.
부모 onClick
이벤트 핸들러를 호출하기 전에 이 핸들러에 코드를 더 추가할 수도 있습니다. 이 패턴은 전파에 대한 대안을 제공합니다. 자식 컴포넌트가 이벤트를 처리하는 동시에 부모 컴포넌트가 몇 가지 추가 동작을 지정할 수 있게 해줍니다. 프로퍼게이션과 달리 자동이 아닙니다. 하지만 이 패턴의 장점은 특정 이벤트의 결과로 실행되는 전체 체인 코드를 명확하게 따라갈 수 있다는 것입니다.
If you rely on propagation and it’s difficult to trace which handlers execute and why, try this approach instead. 전파에 의존하고 있고 어떤 핸들러가 실행되고 왜 실행되는지 추적하기 어려운 경우 대신 이 접근 방식을 시도해 보세요.
Preventing default behavior기본 동작 방지
Some browser events have default behavior associated with them. For example, a <form>
submit event, which happens when a button inside of it is clicked, will reload the whole page by default:
일부 브라우저 이벤트에는 연결된 기본 동작이 있습니다. 예를 들어, <form>
submit 이벤트는 내부의 버튼을 클릭할 때 발생하며 기본적으로 전체 페이지를 다시 로드합니다:
export default function Signup() { return ( <form onSubmit={() => alert('Submitting!')}> <input /> <button>Send</button> </form> ); }
You can call e.preventDefault()
on the event object to stop this from happening:
이벤트 객체에서 e.preventDefault()
를 호출하여 이런 일이 발생하지 않도록 할 수 있습니다:
export default function Signup() { return ( <form onSubmit={e => { e.preventDefault(); alert('Submitting!'); }}> <input /> <button>Send</button> </form> ); }
Don’t confuse e.stopPropagation()
and e.preventDefault()
. They are both useful, but are unrelated:
e.stopPropagation()
과 e.preventDefault()
를 혼동하지 마세요. 둘 다 유용하지만 서로 관련이 없습니다:
e.stopPropagation()
stops the event handlers attached to the tags above from firing.e.preventDefault()
prevents the default browser behavior for the few events that have it.
e.stopPropagation()
은 위 태그에 연결된 이벤트 핸들러의 실행을 중지합니다.e.preventDefault()
는 해당 이벤트가 있는 몇 가지 이벤트에 대해 기본 브라우저 동작을 방지합니다.
Can event handlers have side effects?이벤트 핸들러에 부작용이 생길 수 있나요?
Absolutely! Event handlers are the best place for side effects. 물론입니다! 이벤트 핸들러는 부작용이 가장 많이 발생하는 곳입니다.
Unlike rendering functions, event handlers don’t need to be pure, so it’s a great place to change something—for example, change an input’s value in response to typing, or change a list in response to a button press. However, in order to change some information, you first need some way to store it. In React, this is done by using state, a component’s memory. You will learn all about it on the next page. 렌더링 함수와 달리 이벤트 핸들러는 순수할 필요가 없으므로 타이핑에 대한 응답으로 input 값을 변경하거나 버튼 누름에 대한 응답으로 목록을 변경하는 등 무언가를 변경하기에 좋은 곳입니다. 하지만 일부 정보를 변경하려면 먼저 정보를 저장할 방법이 필요합니다. React에서는 컴포넌트의 메모리인 state를 사용해 이 작업을 수행합니다. 다음 페이지에서 이에 대한 모든 것을 배우게 될 것입니다.
Recap요약
- You can handle events by passing a function as a prop to an element like
<button>
. - Event handlers must be passed, not called!
onClick={handleClick}
, notonClick={handleClick()}
. - You can define an event handler function separately or inline.
- Event handlers are defined inside a component, so they can access props.
- You can declare an event handler in a parent and pass it as a prop to a child.
- You can define your own event handler props with application-specific names.
- Events propagate upwards. Call
e.stopPropagation()
on the first argument to prevent that. - Events may have unwanted default browser behavior. Call
e.preventDefault()
to prevent that. - Explicitly calling an event handler prop from a child handler is a good alternative to propagation.
<button>
과 같은 요소에 함수를 prop으로 전달하여 이벤트를 처리할 수 있습니다.- 이벤트 핸들러는 호출이 아니라 전달해야 합니다!
onClick={handleClick()}
이 아니라onClick={handleClick}
입니다. - 이벤트 핸들러 함수를 개별적으로 또는 인라인으로 정의할 수 있습니다.
- 이벤트 핸들러는 컴포넌트 내부에 정의되므로 props에 액세스할 수 있습니다.
- 부모에서 이벤트 핸들러를 선언하고 이를 자식에게 prop으로 전달할 수 있습니다.
- 이름을 지정하여 이벤트 핸들러 prop을 직접 정의할 수 있습니다.
- 이벤트는 위쪽으로 전파됩니다. 이를 방지하려면 첫 번째 인수에
e.stopPropagation()
을 호출하세요. - 이벤트에 원치 않는 기본 브라우저 동작이 있을 수 있습니다. 이를 방지하려면
e.preventDefault()
를 호출하세요. - 자식 핸들러에서 이벤트 핸들러 prop을 명시적으로 호출하는 것은 전파에 대한 좋은 대안입니다.
Challenge 1 of 2: Fix an event handler이벤트 핸들러 수정하기
Clicking this button is supposed to switch the page background between white and black. However, nothing happens when you click it. Fix the problem. (Don’t worry about the logic inside handleClick
—that part is fine.)
이 버튼을 클릭하면 페이지 배경이 흰색과 검은색으로 전환되어야 합니다. 하지만 이 버튼을 클릭해도 아무 일도 일어나지 않습니다. 문제를 해결하세요. (handleClick
내부의 로직은 걱정하지 마세요. 그 부분은 괜찮습니다.)
export default function LightSwitch() { function handleClick() { let bodyStyle = document.body.style; if (bodyStyle.backgroundColor === 'black') { bodyStyle.backgroundColor = 'white'; } else { bodyStyle.backgroundColor = 'black'; } } return ( <button onClick={handleClick()}> Toggle the lights </button> ); }