Mastering Events
Building interactive applications requires one fundamental capability: responding to user actions. Clicks, keyboard presses, text input, copying, dragging — modern interfaces depend on events.
- •How event handlers work in React
- •The difference between function references and invocations
- •Why event handlers belong inside components
- •How to access event information
- •Building interactive applications with events
React's event system makes this straightforward, but fully understanding how handlers work, how they are passed, and how React invokes them will make you a far more confident developer.
Event Handlers Start as Simple Functions
Imagine we want a button that logs a message when clicked. Start with the UI:
export default function LoggerButton() {
return <button>Log Something</button>
}Now create the event handler:
const handleClick = () => {
console.log("Button clicked")
}And wire it together via React's built-in onClick prop:
export default function LoggerButton() {
const handleClick = () => {
console.log("Button clicked")
}
return <button onClick={handleClick}>Log Something</button>
}This example demonstrates two universal patterns:
- •You encapsulate logic into dedicated event handler functions
- •You pass a function reference, not a result
Reference vs. Invocation: The Most Common Beginner Mistake
These look similar but behave very differently:
<button onClick={handleClick}>Reference</button>
<button onClick={handleClick()}>Invocation</button>- •Passing a reference (handleClick) → React can call it later
- •Passing an invocation (handleClick()) → JavaScript calls it immediately and passes the returned value to onClick
Most of the time, the invocation version breaks your UI because React receives something like undefined instead of a function.
This applies to all props that expect functions, not just event handlers.
Why Event Handlers Live Inside Components
Here's a small button that shows an alert based on a prop:
function AlertButton({ text }) {
const handleClick = () => alert(text)
return <button onClick={handleClick}>Show Alert</button>
}Because the handler is defined inside the component, it automatically receives access to props, state, and anything else in scope.
If we move the handler outside:
function handleClick() {
alert(text) // ❌ ReferenceError
}
function AlertButton({ text }) {
return <button onClick={handleClick}>Show Alert</button>
}You lose access to text. React devs quickly learn that event handlers belong inside components unless there is a very explicit performance reason not to.
"But React Rerenders — Doesn't It Recreate Functions?"
Yes. And it's usually irrelevant.
JavaScript engines are extremely optimized at allocating and freeing functions. A typical React render creates dozens of them; this is normal and expected.
Only in extremely heavy interaction scenarios do you start worrying about stable references — but then you use useCallback or memoization, which belongs in an advanced topic.
Accessing Event Information
Every React event handler receives a Synthetic Event — React's cross-browser wrapper around native browser events.
For example:
function handleChange(e) {
console.log(e.target.value)
console.log(e.timeStamp)
}Useful properties include:
- •target – the element that triggered the event
- •currentTarget – the element the handler is bound to
- •timeStamp – when the event occurred
- •type – the type of event, e.g., "click"
Let's build something practical that relies on event data.
A Real Example: Build a "Fast Typer" Mini-Game
Goal:
Show the user a random word. They must type it and press Enter within 3 seconds.
Step 1: Utilities and UI
const WORDS = ["react", "javascript", "hooks", "state", "props"]
function getRandomWord() {
return WORDS[Math.floor(Math.random() * WORDS.length)]
}Component skeleton:
export default function FastTyper() {
const [word, setWord] = React.useState(() => getRandomWord())
const [startTime, setStartTime] = React.useState(() => Date.now())
return (
<div>
<h2>Type this word:</h2>
<strong>{word}</strong>
<input placeholder="Start typing..." />
<button>Reset</button>
</div>
)
}Step 2: Handle Typing
We must know:
- •What the user typed (e.target.value)
- •When they typed it (Date.now())
function handleKeyDown(e) {
if (e.key !== "Enter") return
const elapsed = Date.now() - startTime
const isCorrect = e.target.value.trim() === word
if (!isCorrect) {
alert("Incorrect word!")
} else if (elapsed > 3000) {
alert("Too slow!")
} else {
alert("Winner!")
}
}Attach the handler:
<input onKeyDown={handleKeyDown} placeholder="Start typing..." />Step 3: Reset Handler
function handleReset() {
setWord(getRandomWord())
setStartTime(Date.now())
}Final JSX:
<button onClick={handleReset}>Reset</button>This example demonstrates:
- •Passing event handlers
- •Reading event data
- •Comparing timestamps
- •Binding handlers in JSX
Full Component for Reference
const WORDS = ["react", "javascript", "hooks", "state", "props"]
const getRandomWord = () => WORDS[Math.floor(Math.random() * WORDS.length)]
export default function FastTyper() {
const [word, setWord] = React.useState(() => getRandomWord())
const [startTime, setStartTime] = React.useState(() => Date.now())
const handleKeyDown = (e) => {
if (e.key !== "Enter") return
const elapsed = Date.now() - startTime
const isCorrect = e.target.value.trim() === word
if (!isCorrect) return alert("Incorrect word!")
if (elapsed > 3000) return alert("Too slow!")
alert("Winner!")
}
const handleReset = () => {
setWord(getRandomWord())
setStartTime(Date.now())
}
return (
<div>
<h2>Type this word:</h2>
<strong>{word}</strong>
<input
autoFocus
placeholder="Start typing…"
onKeyDown={handleKeyDown}
/>
<button onClick={handleReset}>Reset</button>
</div>
)
}All React Events at Your Disposal
React supports a wide range of events:
(click, copy, drag, keydown, blur, submit, wheel, touchstart, animationend, etc.)
Rather than listing them again here, remember the rule:
If the browser supports it, React probably supports it too — with camelCase naming
Summary
Events are at the heart of interactive UI development. Once you understand:
- •passing references
- •placing handlers inside components
- •leveraging lexical scope
- •and using the Synthetic Event object
…you can implement anything from simple button clicks to full-blown interactive games and applications.