튜토리얼 — 입력창 자동 포커스 만들기

RefDemo에서 본 useRef는 숫자를 기억하는 상자였습니다. useRef에는 더 자주 쓰는 용도가 있어요 — DOM 요소를 가리키는 손잡이입니다. 이번엔 페이지가 열리면 검색창에 커서가 저절로 들어가고, 버튼을 누르면 다시 검색창으로 커서가 돌아오는 화면을 만듭니다.
개념
<input> 같은 화면 요소를 자바스크립트로 직접 만지고 싶을 때가 있습니다. "이 입력창에 커서를 넣어라(focus)" 같은 일이죠.
그런데 React에서는 우리가 document.querySelector로 요소를 찾지 않습니다. 대신 useRef로 그 요소를 가리키는 손잡이를 만들고, JSX의 ref={}에 끼워 둡니다. 그러면 React가 화면을 그린 뒤 그 손잡이(ref.current)에 진짜 DOM 요소를 넣어 줍니다.
const inputRef = useRef<HTMLInputElement>(null)→ 손잡이 만들기 (처음엔 비어 있어null)<input ref={inputRef} />→ 손잡이를 이 입력창에 연결inputRef.current?.focus()→ 연결된 입력창에 커서 넣기
RefDemo의 ref는 숫자를, 이번 ref는 DOM 요소를 담습니다. 상자에 담기는 내용물만 다를 뿐 같은 useRef 입니다.
함께 해보기
1단계 — 검색창 컴포넌트 만들기
components/SearchBox.tsx 파일을 만듭니다.
"use client"; import { useRef, useEffect } from "react"; export default function SearchBox() { // 1. <input>을 가리킬 손잡이 — 처음엔 비어 있어 null const inputRef = useRef<HTMLInputElement>(null); // 3. 마운트된 뒤(화면이 그려진 뒤) 입력창에 자동 포커스 useEffect(() => { inputRef.current?.focus(); console.log("자동 포커스: inputRef.current =", inputRef.current); }, []); return ( <div className="p-4 space-y-2"> {/* 2. 손잡이를 이 input에 연결 */} <input ref={inputRef} type="text" placeholder="검색어를 입력하세요" className="rounded border px-3 py-1" /> <button className="rounded bg-blue-500 px-3 py-1 text-white" onClick={() => inputRef.current?.focus()} > 검색창으로 이동 </button> </div> ); }
useRef<HTMLInputElement>(null) — 타입을 적는 이유
이 손잡이가 <input> 요소를 담을 거라고 타입스크립트에게 알려 줍니다. 그래야 inputRef.current.focus()처럼 <input>이 가진 기능을 안전하게 쓸 수 있어요. 처음 값은 null — 아직 화면이 안 그려져서 손잡이가 비어 있기 때문입니다.
?.(옵셔널 체이닝)을 붙이는 이유
inputRef.current는 null일 수 있습니다(연결되기 전). inputRef.current?.focus()는 "비어 있지 않을 때만 focus()를 부른다"는 뜻이라, null일 때 터지는 에러를 막아 줍니다.
왜 useEffect 안에서 포커스를 줄까?
컴포넌트 함수가 실행되는 그 순간엔 아직 <input>이 화면에 없습니다. 그래서 그 시점의 inputRef.current는 null이에요. useEffect는 화면이 다 그려진 뒤에 실행되므로, 그때는 손잡이에 진짜 <input>이 들어 있습니다. DOM을 만지는 코드는 useEffect 안에 둔다 — window를 만질 때와 같은 규칙입니다.
2단계 — 페이지에 올리기
app/search/page.tsx를 만듭니다.
import SearchBox from "@/components/SearchBox"; export default function SearchPage() { return ( <main style={{ padding: 24 }}> <h2>검색창 자동 포커스</h2> <SearchBox /> </main> ); }
3단계 — 확인
/search를 열고 콘솔(F12)을 봅니다.
- 페이지가 열리자마자 검색창에 커서가 깜빡입니다 — 클릭하지 않았는데도요 ✅
- 콘솔에
자동 포커스: inputRef.current = <input ...>가 찍힙니다. 손잡이에 진짜<input>요소가 들어 있다는 증거입니다. - 페이지 빈 곳을 클릭해 포커스를 잃은 뒤, "검색창으로 이동" 버튼을 누릅니다 → 커서가 다시 검색창으로 돌아옵니다.
확인 ✅ — useRef로 만든 손잡이가 실제 <input> 요소를 가리키고 있어서, focus() 같은 DOM 동작을 직접 시킬 수 있었습니다.
만약 콘솔 로그를
useEffect밖(컴포넌트 함수 본문)에 적었다면inputRef.current는null로 찍힙니다. 화면이 그려지기 전이라 손잡이가 아직 비어 있으니까요.
정리
useRef의 두 번째 용도: DOM 요소를 가리키는 손잡이. (RefDemo의 값 기억과 같은 훅, 담는 내용물만 다름)- 손잡이 만들기 → JSX
ref={}에 연결 →ref.current로 요소 사용, 이 세 단계. - 타입은
useRef<HTMLInputElement>(null), 사용은?.로null안전하게. - DOM은 화면이 그려진 뒤에 생기므로, DOM을 만지는 코드는
useEffect안에 둔다.
연습 거리
- 입력창 옆에 "지우기" 버튼을 추가해, 누르면
inputRef.current!.value = ""로 입력값을 비우고 다시 포커스 주기 useState로 입력값 길이를 세어 "N글자" 를 함께 표시하기 (useState + useRef 같이 쓰기)<input>이 두 개일 때, 첫 칸에서 Enter를 누르면 둘째 칸으로 포커스가 넘어가게 만들기 (손잡이 2개)

댓글
댓글을 작성하려면 이 필요합니다.