C.W.K.
Stream
Lesson 03 of 07 · published

Custom Hooks + forwardRef 패턴

~14 min · react, hooks, patterns

Level 0호기심
0 XP0/65 lessons0/17 achievements
0/100 XP to next level100 XP to go0% complete

Custom hook 은 'advanced' 가 아니야 — 정리 방법이지

관련 hook 둘을 한 곳 이상에서 같이 쓴다 싶은 순간, 추출해. 그게 룰 전부야. 컨벤션은 함수 이름 앞에 use 붙이는 거 — React lint 룰이 hook 으로 다루도록 (즉 hook 룰 적용: 조건부 호출 X, 루프 안에서 호출 X).

내 chat sidebar 엔 useConversations() hook. 내 input 엔 useCommandPalette() hook. 내 theme 시스템엔 useTheme() hook. 어느 것도 'advanced' 아니야 — 패턴 반복되니까 자연스럽게 추출한 거지.

forwardRef — parent 가 child DOM 노드 필요할 때

ref 는 보통 props 로 안 흘러. parent 가 child input 의 focus 컨트롤하고 싶으면 forwardRef 필요. React 19 가 단순화: function component 가 ref 를 일반 prop 으로 받을 수 있어. 대부분의 경우 forwardRef wrapper 없어도 됨.

useImperativeHandle — custom ref API 노출

가끔 parent 한테 raw DOM 노드 주기 싫고 — 특정 method (focus(), scrollToBottom()) 만 노출하고 싶고, DOM contract 가 새지 않게 하고 싶을 때. useImperativeHandle 이 child 가 ref 모양 결정하게 해.

언제 쓰나: React 충분히 ship 해서 그게 풀어주는 고통 느끼기 전엔 거의 안 써. 첫 도구로 손 댄다면 view layer 에 imperative 상태 너무 많이 박은 거.

Code

useTheme — 실제 ThemeProvider 의 custom hook·tsx
type Theme = 'dark' | 'light' | 'system';

function useTheme() {
  const [theme, setTheme] = useState<Theme>(() => {
    return (localStorage.getItem('theme') as Theme) ?? 'system';
  });

  useEffect(() => {
    const resolved = theme === 'system'
      ? matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
      : theme;
    document.documentElement.dataset.theme = resolved;
    localStorage.setItem('theme', theme);
  }, [theme]);

  return { theme, setTheme };
}
InputArea with forwardRef — parent can focus the textarea·tsx
interface InputAreaHandle { focus: () => void }

const InputArea = forwardRef<InputAreaHandle, Props>((props, ref) => {
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  useImperativeHandle(ref, () => ({
    focus: () => textareaRef.current?.focus(),
  }), []);
  return <textarea ref={textareaRef} {...props} />;
});

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고
💛 by 똘이warm💛 by 피파warm

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.