728x90

여러개의 컴퍼넌트가 있는 페이지에서 수정하기 버튼이 있습니다. 이때 저는 수정 내용이 많지 않기에 페이지 이동이 아닌 현재 페이지에서  컴퍼넌트를 읽기 컴퍼넌트에서 수정 컴퍼넌트로 변경하여 수정하고 싶었습니다. 이때 수정하려는 컴퍼넌트가 화면의 정중앙에 오도록 하고 싶었습니다.    하지만 focus를 주는 경우는 굉장히 범용적이고 자주 사용할 수 있는 기능입니다. 따라서 저는 이를 커스텀 훅으로 만들려고 하였습니다.

 

최종 코드

import { useEffect } from 'react';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const useFocusRef = (ref: React.MutableRefObject<HTMLInputElement | null>, array: any[], focus?: boolean) => {
	useEffect(() => {
		if (ref.current) {
			focus && ref.current.focus();

			ref.current.scrollIntoView({
				behavior: 'smooth',
				block: 'center',
				inline: 'center',
			});
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, array);

	return useFocusRef;
};

ref의 속성

자연스럽게 스크롤 이동 : behavior ,  수직 가운데 : block , 수평 가운데 :inline 

매개 변수는 대상 ref, 의존성 배열, focus 여부 ( 인풋의 경우에는 포커스 하려고) 3가지를 받았습니다.

 

es-lint와 타입스크립트 환경에서 코드를 작성하였기 때문에 타입 지정을 했고,
eslint에서
any 타입에 대한 error를 무시하기 위한  주석 : eslint-disable-next-line @typescript-eslint/no-explicit-any

의존성 배열의 유효성 검사 무시를 위한 주석 : eslint-disable-next-line react-hooks/exhaustive-deps

 

즐거운 코딩되세요.  아래는 어떻게 구현했는지에 대해서입니다.

 

 

코드 해석 및 코드 구현 과정

 

처음에는 챗지피티한테 물어봐서 쉽게 구현하려고 했습니다. 하지만 화면 정중앙에 위치 시킨다니깐 css를 통해서 위치를 정중앙에 두려고 하더군요. .

좀 더 자세히 물어본 결과 얻은 코드는 아래와 같습니다.

import { useEffect } from 'react';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const useFocusRef = (ref: React.MutableRefObject<HTMLInputElement | null>, array: any[]) => {
	useEffect(() => {
		if (ref.current) {
			ref.current.focus();
			const windowHeight = window.innerHeight;
			const elementTop = ref.current.getBoundingClientRect().top;
			const offset = elementTop - windowHeight / 2;

			// 스크롤 위치 조절
			window.scrollTo({
				top: window.scrollY + offset,
				behavior: 'smooth',
			});
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, array);

	return useFocusRef;
};

타입스크립트 esLint를 쓰기 때문에 주석문을 추가했습니다.

각각의 요소중 getBoundingCliendRect는 해당 ref의 위치를 구하는 것 입니다.

화면의 높이를 구하고, (innerHeight)

요소의 위쪽 위치를 구하고 (elementTop)

offset 화면이 얼만큼 이동해야지 현재 뷰포트 기준으로 가운데가 될 지 정해줍니다.

이때 스크롤 높이도 고려해야하기에 이동할 때는 window.scrollY를 구한후에  이동을 합니다.

 

기능 자체는 정상 구현했지만, ref 속성들에서 좀 더 잘 알고 싶어서 공식문서를 찾게 되었습니다.

돔요스를 ref로 관리하는 방법에 대한 페이지가 공식문서에 존재하더군요.

https://react.dev/learn/manipulating-the-dom-with-refs

 

Manipulating the DOM with Refs – React

The library for web and native user interfaces

react.dev

 

이중에서  scrollIntoView라는 옵션에서 화면에 정중앙 시키는 방법이 있는 것을 확인하고 적용시켰습니다.

원래 코드는 세로로 가운데 위치하도록만 했는데, 이 방식은 가로(.inline)으로도 가운데 위치 시키는게 되더군요.

코드 가독성도 훨씬 높아집니다.

따라서 윈도우 객체를 통해 이동하던 코드를 수정하였습니다.

이후에 인풋이 아닌 경우에도 포커스를 주고 싶을 수 있기에  focus라는 3번째 인자를 통해서  해당 값에 true가 온다면 focus를 주도록 하였습니다.

 

그 결과 완성된 코드가 페이지 첫 부분에 있는 코드입니다.

import { useEffect } from 'react';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const useFocusRef = (ref: React.MutableRefObject<HTMLInputElement | null>, array: any[], focus?: boolean) => {
	useEffect(() => {
		if (ref.current) {
			focus && ref.current.focus();

			ref.current.scrollIntoView({
				behavior: 'smooth',
				block: 'center',
				inline: 'center',
			});
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, array);

	return useFocusRef;
};

사용 방법은 아래와 같이.

	useFocusRef(newRoomCategory, []);

+ Recent posts