제가 팀프로젝트에서 이번에 적용해야 할 것은 유저가 버튼(전체 스터디 보기)을 클릭했을 때, 자동으로 전체 스터디 컴포넌트로 스크롤 되는 동작을 구현해야 합니다:) 그럼 먼저 useRef에 대해 알아보도록 하겠습니다.
1. useRef란?
React 공식 홈페이지에서는 ".current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환합니다. 반환된 객체는 컴포넌트의 전 생애주기를 통해 유지될 것입니다." 라고 설명하고 있습니다.
쉽게 말하자면, useRef의 Ref는 reference(참조)의 줄임말로 저장공간 또는 DOM 요소에 접근하기 위해 사용되는 React Hook입니다. 주요한 특징은 특정한 DOM 요소에 접근이 가능하며, 불필요한 재렌더링을 하지 않는다는 장점이 있습니다.
2. useRef의 기본 형식
1. 생성
const 변수명 = useRef(초기값)
useRef는 변수명에 초기값을 적는 식으로 만듭니다. => 이러한 결과값으로, { current: 초기값 }을 지닌 객체가 반환된다. 접근할때는 변수명.current 값으로 접근합니다.
2. 반환 요소에 접근
<input ref={변수명}/>
3. 특징
반환된 useRef 객체는 컴포넌트의 전생애주기를 통해 유지됩니다.
- 컴포넌트가 계속해서 렌더링 되어도 컴포넌트가 언마운트 되기 전까지는 값을 그대로 유지할 수 있습니다.
- current 속성은 값을 변경해도 상태를 변경할 때처럼 React 컴포넌트가 재렌더링 되지 않습니다.
❗렌더링과 상관없이 마운트된 시점부터 언마운트 되는 시점까지 재렌더링 되지 않고 값을 유지합니다.❗
4. 언제 사용하나요?
< 저장 공간 >
const countRef = useRef(0);
// 값 변경해도 리렌더링 발생하지 않음
countRef.current = countRef.current + 1;
- useState => 저장된 값 변경 => 렌더링
- useRef => 저장된 값 변경 => No 렌더링 => 성능 향상 ✅
변경시 렌더링을 발생 시키지 말아야 하는 값을 다룰 때 사용합니다. (변화는 감지해야 하지만, 그 변화가 렌더링을 발생시키면 안될 때❗❗)
< DOM 요소에 접근 >
const elementRef = useRef<HTMLDivElement>(null);
// 이렇게 사용
<div ref={elementRef}>내용</div>
// DOM 조작 예시
elementRef.current?.scrollIntoView();
elementRef.current?.focus();
useRef를 사용하면 손쉽게 DOM 요소에 접근할 수 있습니다.
- input 요소에 focus 추가 (자동 포커스)
- input 값을 직접 조작하기 (제어되지 않는 컴포넌트)
- 스크롤 위치 케어(스크롤 컨테이너)
- 이벤트 리스너/구독 참조 저장
예시 코드:
// input 포커스 예시
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>포커스</button>
</>
);
// 타이머 ID 저장 예시
const timerRef = useRef(null);
const startTimer = () => {
timerRef.current = setInterval(() => {
console.log("타이머 실행 중...")
}, 1000)
};
const stopTimer = () => {
clearInterval(timerRef.current);
};
5. 내 프로젝트에 자동스크롤 적용
import styled from "@emotion/styled";
import Carousel from "@/components/organisms/hub/Carousel/Carousel";
import ModalButton from "@/components/organisms/hub/ModalButton/ModalButton";
import TopStudy from "@/components/organisms/hub/TopStudy/TopStudy";
import Deadline from "@/components/organisms/hub/Deadline/Deadline";
import SectionTopic from "@/components/organisms/hub/SectionTopic/SectionTopic";
import SectionReview from "@/components/organisms/hub/SectionReview/SectionReview";
import SectionTotalView from "@/components/organisms/hub/SectionTotalView/SectionTotalView";
import { useRef } from "react";
const StudyHubPage = () => {
const scrollDownRef = useRef<HTMLDivElement>(null);
const scrollToRef = () => {
scrollDownRef.current?.scrollIntoView({
behavior: "smooth",
block: "start",
});
};
return (
<BackGround>
<MainContainer>
<Carousel />
<ModalButton />
<TopStudy onClick={scrollToRef} />
<Deadline />
<SectionTopic />
<SectionReview />
<div ref={scrollDownRef}>
<SectionTotalView />
</div>
</MainContainer>
</BackGround>
);
};
export default StudyHubPage;
const BackGround = styled.div`
width: 100%;
`;
const MainContainer = styled.div`
width: 100%;
`;
import { Text } from "@teamsparta/stack-text";
import { vars } from "@teamsparta/stack-tokens";
import { ArrowChevronDown } from "@teamsparta/stack-icons";
import StudyCard from "../common/StudyCard";
import { studyCardData } from "@/models/hub/topStudy.model";
import * as S from "./topStudy.style";
type TopStudyType = {
onClick: () => void;
};
const TopStudy = ({ onClick }: TopStudyType) => {
return (
<S.Background>
<Text as="p" font="subTitle2" color={vars.text.primary}>
2월 인기 TOP5 스터디
</Text>
<S.CardContainer>
{studyCardData.map((card) => {
return (
<StudyCard
key={card.id}
id={card.id}
thumbnail={card.thumbnail}
title={card.title}
startDate={card.startDate}
tags={card.tags}
rank={card.rank}
/>
);
})}
</S.CardContainer>
<S.AllStudyButton onClick={onClick}>
<Text as="p" font="captionSb" color={vars.neutral[50]}>
전체 스터디 보기
</Text>
<ArrowChevronDown size={16} color="#9DA7AE" />
</S.AllStudyButton>
</S.Background>
);
};
export default TopStudy;
'인턴' 카테고리의 다른 글
[ Troubleshooting🛠️ ] HTML <picture>과 <source> 태그 활용하기 (0) | 2025.03.25 |
---|---|
Vercel CLI을 이용한 환경변수 세팅 (0) | 2025.03.25 |
[ Troubleshooting🛠️ ] Git 파일명 대소문자 구분 문제 해결하기 (0) | 2025.03.14 |
말줄임표: ellipsis (0) | 2025.03.04 |
Route Handler (0) | 2025.02.12 |