---
type: snippet
tags:
  [
    'react',
    'react-19',
    'hooks',
    'ref-callback',
    'use-click-outside',
    'event-listener',
    'cleanup',
  ]
status: release
ctime: 2026-06-07
mtime: 2026-06-07
---

**useClickOutside — ref callback 방식 정리**

- ref callback은 DOM 노드 참조만 전달할 뿐, 내부에서 등록한 이벤트 리스너 등의 사이드이펙트는 자동 해제되지 않음
- React 18 이하: unmount 시 `callback(null)` 호출되지만, 동일 함수 참조가 없어 `removeEventListener` 곤란 → 별도 ref 저장 필요
- React 19: `useEffect`처럼 cleanup function return을 공식 지원 → `return () => removeEventListener(...)` 패턴 사용 가능
- stale closure 방지는 `handlerRef.current = handler` 패턴으로 해결
- 결론: React 19라면 ref callback + cleanup return이 `useEffect` 방식의 깔끔한 대안

```ts
function useClickOutside(handler) {
  const handlerRef = useRef(handler);
  handlerRef.current = handler;

  return useCallback((node) => {
    const handleClick = (e) => {
      if (!node.contains(e.target)) handlerRef.current();
    };

    document.addEventListener('mousedown', handleClick);
    return () => document.removeEventListener('mousedown', handleClick);
  }, []);
}

// 사용
function Modal({ onClose }) {
  const ref = useClickOutside(onClose);
  return <div ref={ref}>...</div>;
}
```

## 참고

- [React v19 — Cleanup functions for refs](https://react.dev/blog/2024/12/05/react-19)
