What Song은 실시간 음악 스트리밍 기반 SNS로 뮤직룸에서 플레이리스트를 동시에 같이 듣는 서비스를 제공하는 프로젝트다.
그 중에서 뮤직룸 생성 기능을 스크롤 이벤트로 동작하는 페이지로 만들어보기로 했다.
구현할 기능은 다음과 같다.
useRef
는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환합니다. 반환된 객체는 컴포넌트의 전 생애주기를 통해 유지될 것입니다. - React 공식 사이트
querySelector
, getElelmentById
등을 이용하여 특정 DOM을 선택하고 조작한다.document.getElementById()
으로 접근했을 때 문제가 발생할 수 있다!const inputRef = useRef(null)
<input ref={inputRef} type="text" />
<button onClick={()=> inputRef.current.focus()}>
input으로 포커스 </button>
호출된 엘리멘트가 있는 위치로 스크롤을 이동시키는 자바스크립트 내장 메서드이다. 인자로 true/false값 또는 option 객체를 받을 수 있다.
scrollIntoViewOptions: {block: "start", inline: "nearest"}
와 동일함scrollIntoViewOptions: {block: "end", inline: "nearest"}
와 동일함{ behavior: "auto"/”instant/"smooth" }
: 스크롤 시 즉시 적용할지, 부드러운 애니메이션 적용할지{ block:"start"/"center"/"end"/"nearest" }
: 수직 요소에 대한 옵션, 어느 선에서 멈출 지, default = start{ inline: "start"/"center"/"end"/"nearest" }
, 수평 요소에 대한 옵션, 어느 선에서 멈출 지, default = nearest// 스크롤 이동을 위한 useRef 객체 선언
const focusFirst = useRef<HTMLDivElement>(null);
const focusSecond = useRef<HTMLDivElement>(null);
const focusLast = useRef<HTMLDivElement>(null);
// 스크롤 포커스하는 함수
const onMoveToFocus = (focus: React.RefObject<HTMLDivElement>) => {
focus.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
};
behavior: 'smooth'
, ref의 제일 상단으로 이동하는 block: 'start'
{/* 플레이리스트 이름 Input Section */}
<section ref={focusFirst}>
...
<button onClick={() => onMoveToFocus(focusSecond)} disabled={data.roomName === ''}>다음</button>
</section>
{/* 플레이리스트 카테고리 선택 Section */}
<section ref={focusSecond}>
...
<button onClick={() => onMoveToFocus(focusLast)}>다음</button>
</section>
{/* 플레이리스트 공개 범위 선택 Section */}
<section ref={focusLast}>
...
<button onClick={onAddRoom} disabled={data.accessAuth === ''}>생성</>
</section>
어렵지 않은 기능이지만 단순히 구현에만 집중하지 않고 사용하는 웹 API에 대해 공부하고 정리해보니 기억에 더 잘 남는 것 같다. 생성 페이지에서 남은 기능은 기능3이다!
기능3
[버튼이 아닌 그냥 스크롤로 이동을 해도 입력 화면으로 focus]를 구현하기 위해서 IntersectionObsever API
를 사용하려고 한다. 다음 글에 이어서 정리해보겠다.
또 Next.js 페이지 컴포넌트에서 바로 짠 코드이기 때문에 섹션 3개가 나열되어 있어서 가독성이 아쉽다.
가독성과 유지보수를 위해서 컴포넌트화하고, 재사용성도 생각해보며 리팩토링할 예정이다.
참고자료
https://simsimjae.tistory.com/417
https://amyhyemi.tistory.com/244?category=873656
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
https://velog.io/@dosilv/ReactWeb-API-useRef-scrollIntoView