Section 8 Refs and Portals
오늘, section 9은 일부만 들었기에, 8파트만 작성 함.
TIL1) Refs(참조) 소개: Refs(참조)로 HTML 요소 연결 및 접근
React에서 Refs(참조)를 사용하면, 컴포넌트의 DOM 요소에 직접 접근할 수 있다. 보통 React는 상태(state)를 통해 UI를 업데이트하는데, 특정 상황에서는 DOM에 직접 접근할 필요가 생길 때가 있다. 예를 들어, 포커스 설정이나 애니메이션 트리거 같은 작업에서 유용하다.
current는 Refs 객체의 중요한 속성으로, HTML 요소나 컴포넌트 인스턴스에 대한 참조를 담고 있다.
Refs는 useRef 또는 createRef 훅을 통해 생성되며, JSX 요소에 연결하면 해당 DOM 요소에 접근할 수 있게 된다. 이를 통해 직접적인 DOM 조작이나 특정 요소의 속성 값을 읽고 수정할 수 있다.
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus(); // current 속성을 통해 input 요소에 접근
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
current는 Refs 객체가 가리키는 실제 DOM 요소나 컴포넌트 인스턴스를 의미한다. 초기에는 null로 설정되어 있지만, 컴포넌트가 렌더링되면 current에 연결된 DOM 요소가 저장된다.
import React, { useRef } from 'react';
function ImageComponent() {
const imageRef = useRef(null); // useRef로 초기값 null 설정
const handleImageClick = () => {
if (imageRef.current) {
// current로 이미지 요소에 접근해서 너비를 콘솔에 출력
console.log(imageRef.current.width);
imageRef.current.style.border = '2px solid blue'; // 이미지에 스타일 적용
}
};
return (
<div>
<img
ref={imageRef} // 이미지 요소에 ref 연결
src="https://example.com/sample.jpg"
alt="Sample"
width="300"
/>
<button onClick={handleImageClick}>Show Image Width</button>
</div>
);
}
export default ImageComponent;
배운점
Refs(참조)는 상태 변경 없이 DOM에 직접 접근할 수 있게 해준다.
current 속성은 Refs 객체에서 중요한 역할을 하며, 렌더링된 DOM 요소에 대한 실시간 접근을 가능하게 한다.
React의 일반적인 흐름인 상태 기반 UI 업데이트와는 달리, Refs는 비제어 컴포넌트에 접근할 때 주로 사용된다.
TIL2) userImperativeHandle 훅으로 컴포넌트 API 노출시
useImperativeHandle 훅은 부모 컴포넌트가 자식 컴포넌트의 특정 기능을 직접 호출할 수 있도록, 자식 컴포넌트의 인스턴스 메서드를 노출하는 데 사용된다. 기본적으로 React에서는 부모가 자식의 DOM 요소나 내부 메서드에 접근할 수 없지만, useImperativeHandle을 사용하면 그 제한을 극복할 수 있다.
주로 ref를 사용해 DOM에 접근하거나, 자식 컴포넌트의 특정 기능을 부모 컴포넌트에서 실행할 필요가 있을 때 유용하다.
import React, { useImperativeHandle, useRef, forwardRef } from 'react';
// 자식 컴포넌트
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus(); // 부모가 호출할 수 있는 메서드 노출
},
clear: () => {
inputRef.current.value = ''; // 입력 필드 초기화
},
}));
return <input ref={inputRef} type="text" />;
});
// 부모 컴포넌트
function ParentComponent() {
const inputRef = useRef();
return (
<div>
<CustomInput ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>Focus Input</button>
<button onClick={() => inputRef.current.clear()}>Clear Input</button>
</div>
);
}
export default ParentComponent;
CustomInput: 자식 컴포넌트로, useImperativeHandle 훅을 사용해 두 가지 메서드(focus, clear)를 부모 컴포넌트에서 사용할 수 있도록 노출함.
ParentComponent: 부모 컴포넌트로, ref를 통해 자식 컴포넌트의 focus와 clear 메서드를 호출함.
React에서는 자식 컴포넌트의 내부에 접근하는 것이 권장되지 않지만, useImperativeHandle은 필요한 기능을 제한적으로 노출해 부모가 자식의 특정 메서드만 호출하도록 제어할 수 있다. 이를 통해 컴포넌트 간의 결합도를 낮추고, 필요한 기능만 외부에 제공할 수 있다.
배운점
useImperativeHandle 훅은 컴포넌트의 인스턴스를 노출해, 부모가 자식 컴포넌트의 특정 기능을 호출할 수 있게 한다.
이 훅은 forwardRef와 함께 사용되며, 자식 컴포넌트가 직접 DOM에 접근하거나 메서드를 노출하는 대신, 부모에게 필요한 인터페이스만 제공한다.
TIL3) useImperativeHandle와 clearInterval을 통한 타이머 및 다이얼로그 관리
React에서 특정 조건에 따라 타이머를 관리하거나 다이얼로그(모달)를 제어할 때, clearInterval과 같은 타이머 관리 함수와 useRef로 다이얼로그에 접근하는 방법이 유용하다.
다음 코드는 타이머가 0이 될 때 타이머를 초기화하고 모달 다이얼로그를 띄우는 방식의 예시다.
if (timeRemaining <= 0) {
clearInterval(time.current); // 현재 타이머 종료
setTimeRemaining(targetTime * 1000); // 타이머 초기화
dialog.current.showModal(); // 모달 다이얼로그 열기
}
clearInterval(time.current): 타이머가 0이 되었을 때 타이머를 중지하는 함수. setInterval로 시작한 타이머를 종료하려면 해당 타이머의 ID가 필요하며, 이 값을 useRef로 관리.
setTimeRemaining(targetTime * 1000): 타이머가 끝났을 때 새로 리셋하는 로직. 남은 시간을 다시 설정하여 새로운 카운트다운을 시작할 수 있다.
dialog.current.showModal(): 모달 다이얼로그를 제어하는 부분. dialog는 useRef로 연결된 DOM 요소로, 모달 창을 열기 위해 showModal() 메서드를 호출.
배운점
clearInterval과 타이머 관리: useRef로 타이머 ID를 저장하고 clearInterval을 통해 타이머를 종료하는 방법을 익혔다. 이를 통해 특정 조건에 따라 타이머를 동적으로 제어할 수 있었다.
모달 팝업 제어: useRef를 사용해 DOM 요소에 접근하고, current 속성으로 모달을 제어하는 방식을 배웠다. dialog.current.showModal()로 다이얼로그를 열 수 있는 기능이 매우 유용했다. 특히 타이머와 연동해서 모달을 띄우는 방식이 인상적이었다.
프로젝트에서의 활용: 최종 프로젝트에서는 단순한 모달 팝업만 사용했지만, 이번에 배운 내용을 바탕으로 타이머나 조건에 따라 동적으로 모달을 제어할 수 있다는 점을 깨달았다. 앞으로는 상황에 맞게 더 정교한 사용자 경험을 제공할 수 있을 것이다.
useRef의 활용성: useRef를 활용해 DOM 요소와 타이머 같은 비동기 작업을 관리하는 것이 효율적이라는 점을 실감했다. useImperativeHandle처럼 컴포넌트 외부에 필요한 기능만 노출하는 방식도 유용하다는 것을 느꼈다.
Learned
오늘 학습한 내용은 Refs와 useImperativeHandle, 그리고 타이머 관리 및 모달 제어에 관한 것이었다. 먼저 Refs는 상태를 거치지 않고도 DOM 요소에 접근할 수 있게 해주는 기능으로, 주로 포커스 설정이나 애니메이션과 같은 작업에서 유용하게 사용된다. 특히 current 속성을 통해 렌더링된 DOM 요소에 실시간으로 접근하는 방법을 익히면서, 상태 업데이트 없이도 UI를 조작할 수 있는 강력함을 실감했다.
또한, useImperativeHandle을 통해 부모 컴포넌트에서 자식 컴포넌트의 특정 기능을 호출할 수 있었다. 이는 컴포넌트 간 결합도를 낮추면서도 필요한 메서드만 노출할 수 있게 해주는 유용한 방식이었다. 특히 forwardRef와 함께 사용되며, 타이머와 모달 다이얼로그를 동적으로 제어할 때 그 활용성이 뛰어나다는 점을 배웠다.
최종 프로젝트에서는 단순한 모달 팝업만 사용했지만, 이번 학습을 통해 타이머와 모달을 연동해 더 정교한 사용자 경험을 제공할 수 있을 것이라는 확신이 들었다. 앞으로 다양한 기능을 구현할 때, 이러한 패턴을 적극적으로 활용할 계획이다.
질문 준비하기