useRef
자바스크립트에선 getElementById,
querySelector
등을 사용하여 html 돔 요소에 접근 가능하여 요소의 속성값을 바꾸는 것이 가능했다.
--html--
<div>Hi!</div>
--html--
//JS에서 HTML파일의div 요소에 접근하는 방법
const div = document.querySelector("div");
setTimeout(() => {
div.innerText = "Bye!";
}, 2000)
리액트 함수형 컴포넌트에선 Ref API를 사용하여 useRef hook
을 이용하여 돔 요소에 접근할 수 있다. (특정 요소의 크기를 선택, 스크롤바의 위치를 가져와서 설정해야 하는 경우 등등)
export const UseRefPractice: React.FC = () => {
//useRef의 제네릭에 담고자 하는 값의 타입을 넣어준다
//인자(초기값)로 보통 null이 전달된다.
//(null을 넣어주는 이유 : 명시적으로 빈 레퍼런스가 생성되었음을 알려 주기 위해)
const divRef = useRef<HTMLDivElement>(null);
console.log("컴디마 전의 ref 값", divRef); //null 이 출력
useEffect(() => {
//컴포넌트 내에서 useRef의 반환 값을 사용할 땐 null check가 필수이다.
//실제 ref에 요소가 담기는 시점은 컴디마에서 담기므로 null check를 해준다.
//(이 체크를 해주지 않으면 TS error가 뜬다)
setTimeout(() => {
if (divRef && divRef.current) {
divRef.current.innerText = "Bye!";
console.log("컴디마 이후의 ref 값", divRef); //div 출력
}
}, 2000);
}, []);
return (
<div>
<h4>Welcome to visit our website!😉</h4>
<div ref={divRef}>Hi!</div>
</div>
);
};
React의 Ref 변수는 변경 가능한 객체이지만 값은 다시 렌더링하는 동안 React에 의해 유지된다. ref 객체는 이름이 current
인 하나의 프로퍼티를 가지고 구조는 { current: ReactElementReference }
와 같다. 컴포넌트의 리렌더링 동안, DOM 요소는 그 동안 업데이트를 받게 된다. 그리고 DOM 요소에 있는 ref 또한 업데이트를 받게 된다. ref가 있는 요소가 업데이트 되지 않는 경우 ref는 유지된다.
useRef는 DOM references 대신 값을 저장하는 방법으로도 사용 될 수 있다(변수를 관리하는 역할). useRef에 저장되는 값은 너무 자주 바뀔 필요가 없거나 자주 변경되지만 컴포넌트의 전체를 리렌링하지 않는 상태인 경우에 해당한다. useRef 로 저장되는 값은 컴포넌트를 리렌더링하지 않고 설정 후 바로 조회 할 수 있으므로 아래의 경우에 사용하는 것이 유용하다.
export const UseRefPractice = () => {
let isClicked = useRef(false);
console.log("클릭이벤트 전의 상태", isClicked);
const clickHandler = () => {
//클릭이벤트에 따라 ref 값은 변경된다
isClicked.current = !isClicked.current;
console.log("클릭중", isClicked);
};
return (
<section>
<h3 onClick={clickHandler}>This is Title</h3>
{/* ref 상태 값은 변경되지만 리렌더링이 이루어지지 않으므로
ref값에 따라서 리턴되는 결과엔 영향을 주지 않는다.
-> refs는 컴포넌트의 라이프사이클에서 같은 값을 홀드하기 때문이다 */}
{isClicked && <p>It's Clicked!</p>}
</section>
);
};
setTimeout
, setInterval
을 통해서 만들어진 id
export const UseRefPractice = () => {
const divRef = useRef<HTMLDivElement>(null);
const scrollingToTop = () => {
if (divRef && divRef.current) {
divRef.current.scrollIntoView({ behavior: "smooth" });
}
};
return (
<div ref={divRef}>
<ListContainer>
{MENU_LIST.map((menu, idx) => {
return <li key={idx}>{menu.menu}</li>;
})}
</ListContainer>
{MENU_LIST.map((src, idx) => {
return <Img alt={src.menu} src={src.src} key={idx} />;
})}
<button onClick={scrollingToTop}>TOP!</button>
</div>
);
};
A Thoughtful Way To Use React's useRef() Hook - Smashing Magazine