React 개발을 하다 보면 가장 많이 쓰는 훅 중 두 가지가 useState와 useRef입니다. 둘 다 컴포넌트 내부에서 값을 관리할 때 사용하지만, 동작 방식과 사용 목적이 확연히 다릅니다. 이 글에서는 useState와 useRef가 어떤 훅인지 간단히 설명하고, 언제 어떤 상황에서 사용하는 것이 적절한지 예제와 함께 정리해 보겠습니다. 🤓
useState는 컴포넌트의 상태(state)를 선언하는 훅입니다. 상태가 변경되면 컴포넌트가 리렌더링되며, UI도 그에 맞게 다시 그려집니다.
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
상태 값이 바뀔 때마다 컴포넌트는 다시 렌더링됩니다. 비동기적으로 동작하며, 렌더링 결과에 직접적인 영향을 줍니다.
useRef는 변경 가능한 값을 저장할 수 있는 훅입니다. useState와 달리 값이 변경되어도 컴포넌트가 리렌더링되지 않습니다.
const countRef = useRef(0);
const handleClick = () => {
countRef.current += 1;
console.log(countRef.current); // 리렌더 없이 값 증가
};
또한, DOM 요소에 직접 접근할 때도 많이 사용합니다.
const inputRef = useRef<HTMLInputElement>(null);
const focusInput = () => {
inputRef.current?.focus();
};
return <input ref={inputRef} />;
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
console.log(count); // 아직 이전 값이 출력됨
};
setCount를 호출해도 그 즉시 count 값이 바뀌지 않습니다. 변경은 React가 다음 렌더링을 할 때 반영됩니다. React가 여러 상태 업데이트를 batching해서 처리하려고 비동기적으로 관리하기 때문입니다.
📌 그래서 useState는 변경 즉시 값을 반영해야 하는 로직(예: 카운터 누적, 이전값 비교 등)과 함께 쓸 땐 주의가 필요합니다. useState의 비동기적 업데이트 특성 때문에 “이전 값”을 기준으로 상태를 갱신하는 로직에서 버그가 생기기 쉽기 때문입니다.
const countRef = useRef(0);
const handleClick = () => {
countRef.current += 1;
console.log(countRef.current); // 증가된 값이 즉시 출력됨
};
useRef.current는 그냥 JS 변수처럼 동작합니다. 즉시 업데이트되고, React는 이 변경을 전혀 신경 쓰지 않습니다. Godd job, useRef 👍
Godd job, useState