React Event Handling Cheat Sheet

Basic Event Handling

Event Handler Syntax

// Inline handler
<button onClick={() => console.log('clicked')}>Click me</button>

// Named function
function handleClick() {
  console.log('clicked');
}
<button onClick={handleClick}>Click me</button>

// With parameters
<button onClick={(e) => handleClick(e, 'param')}>Click me</button>

Common Event Types

// Mouse events
onClick, onDoubleClick, onMouseEnter, onMouseLeave
onMouseDown, onMouseUp, onMouseMove

// Keyboard events
onKeyDown, onKeyUp, onKeyPress

// Form events
onChange, onSubmit, onFocus, onBlur, onInput

// Touch events
onTouchStart, onTouchEnd, onTouchMove

// Clipboard events
onCopy, onCut, onPaste

Synthetic Events

Event Object Properties

function handleClick(event) {
  // Prevent default behavior
  event.preventDefault();
  
  // Stop propagation
  event.stopPropagation();
  
  // Event target
  console.log(event.target); // DOM element
  console.log(event.currentTarget); // React component
  
  // Event type
  console.log(event.type); // 'click'
  
  // Timestamp
  console.log(event.timeStamp);
}

Event Pooling (React 16 and earlier)

// Don't access event asynchronously in React 16-
function handleClick(event) {
  // Wrong - event might be null
  setTimeout(() => console.log(event.target), 100);
  
  // Correct - extract values immediately
  const target = event.target;
  setTimeout(() => console.log(target), 100);
}

Event Handling Patterns

Controlled Components

function ControlledInput() {
  const [value, setValue] = useState('');
  
  const handleChange = (event) => {
    setValue(event.target.value);
  };
  
  return (
    <input
      type="text"
      value={value}
      onChange={handleChange}
    />
  );
}

Event Delegation

function ListWithDelegation() {
  const handleClick = (event) => {
    if (event.target.matches('li')) {
      console.log('List item clicked:', event.target.textContent);
    }
  };
  
  return (
    <ul onClick={handleClick}>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
    </ul>
  );
}

Conditional Event Handling

function ConditionalHandler({ isEnabled }) {
  const handleClick = isEnabled ? () => console.log('enabled') : undefined;
  
  return (
    <button onClick={handleClick} disabled={!isEnabled}>
      Click me
    </button>
  );
}

Advanced Event Handling

Custom Hooks for Events

function useEventListener(eventName, handler, element = window) {
  useEffect(() => {
    element.addEventListener(eventName, handler);
    return () => element.removeEventListener(eventName, handler);
  }, [eventName, handler, element]);
}

// Usage
function Component() {
  const handleKeyPress = useCallback((event) => {
    if (event.key === 'Escape') {
      console.log('Escape pressed');
    }
  }, []);
  
  useEventListener('keydown', handleKeyPress);
  
  return <div>Press Escape</div>;
}

Event Handler Optimization

function OptimizedComponent() {
  // Memoize handlers to prevent re-renders
  const handleClick = useCallback((id) => {
    console.log('Item clicked:', id);
  }, []);
  
  const handleSubmit = useCallback((event) => {
    event.preventDefault();
    // Handle form submission
  }, []);
  
  return (
    <form onSubmit={handleSubmit}>
      {items.map(item => (
        <button key={item.id} onClick={() => handleClick(item.id)}>
          {item.name}
        </button>
      ))}
    </form>
  );
}

Debounced Event Handlers

function useDebounce(callback, delay) {
  const timeoutRef = useRef();
  
  return useCallback((...args) => {
    clearTimeout(timeoutRef.current);
    timeoutRef.current = setTimeout(() => callback(...args), delay);
  }, [callback, delay]);
}

// Usage
function SearchInput() {
  const [query, setQuery] = useState('');
  
  const debouncedSearch = useDebounce((searchTerm) => {
    // Perform search API call
    console.log('Searching for:', searchTerm);
  }, 300);
  
  const handleChange = (event) => {
    const value = event.target.value;
    setQuery(value);
    debouncedSearch(value);
  };
  
  return <input value={query} onChange={handleChange} />;
}

Form Event Handling

Form Submission

function ContactForm() {
  const handleSubmit = (event) => {
    event.preventDefault();
    
    const formData = new FormData(event.target);
    const data = Object.fromEntries(formData);
    
    // Submit data
    console.log('Form data:', data);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input name="name" type="text" required />
      <input name="email" type="email" required />
      <button type="submit">Submit</button>
    </form>
  );
}

Input Validation

function ValidatedInput() {
  const [value, setValue] = useState('');
  const [error, setError] = useState('');
  
  const handleChange = (event) => {
    const newValue = event.target.value;
    setValue(newValue);
    
    // Validate
    if (newValue.length < 3) {
      setError('Must be at least 3 characters');
    } else {
      setError('');
    }
  };
  
  return (
    <div>
      <input
        value={value}
        onChange={handleChange}
        className={error ? 'error' : ''}
      />
      {error && <span className="error-text">{error}</span>}
    </div>
  );
}

Keyboard Event Handling

Keyboard Shortcuts

function KeyboardShortcuts() {
  useEffect(() => {
    const handleKeyDown = (event) => {
      // Ctrl/Cmd + S
      if ((event.ctrlKey || event.metaKey) && event.key === 's') {
        event.preventDefault();
        console.log('Save triggered');
      }
      
      // Escape key
      if (event.key === 'Escape') {
        console.log('Cancel triggered');
      }
      
      // Arrow keys
      switch (event.key) {
        case 'ArrowUp':
          console.log('Navigate up');
          break;
        case 'ArrowDown':
          console.log('Navigate down');
          break;
      }
    };
    
    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, []);
  
  return <div>Use keyboard shortcuts</div>;
}

Focus Management

function FocusableComponent() {
  const inputRef = useRef();
  
  const handleKeyDown = (event) => {
    if (event.key === 'Enter') {
      inputRef.current.focus();
    }
  };
  
  return (
    <div onKeyDown={handleKeyDown}>
      <button>Press Enter to focus input</button>
      <input ref={inputRef} placeholder="This will be focused" />
    </div>
  );
}

Best Practices

Performance Optimization

// Good - Memoize handlers
const handleClick = useCallback(() => {
  // Handler logic
}, [dependencies]);

// Good - Use event delegation for lists
<ul onClick={handleListClick}>
  {items.map(item => <li key={item.id}>{item.name}</li>)}
</ul>

// Avoid - Inline functions in render
<button onClick={() => handleClick(id)}>Click</button>

Accessibility

// Good - Keyboard support
<div
  onClick={handleClick}
  onKeyDown={(e) => e.key === 'Enter' && handleClick()}
  tabIndex={0}
  role="button"
  aria-label="Clickable element"
>
  Click me
</div>

// Good - Screen reader support
<button
  onClick={handleClick}
  aria-describedby="button-description"
>
  Submit
</button>
<div id="button-description">Submits the form data</div>

Error Handling

function SafeEventHandler() {
  const handleClick = (event) => {
    try {
      // Event handling logic
      processEvent(event);
    } catch (error) {
      console.error('Event handling error:', error);
      // Fallback behavior
    }
  };
  
  return <button onClick={handleClick}>Safe Click</button>;
}

Cleanup

function ComponentWithCleanup() {
  useEffect(() => {
    const handleResize = () => {
      // Handle resize
    };
    
    window.addEventListener('resize', handleResize);
    
    // Cleanup function
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);
  
  return <div>Component with cleanup</div>;
}