본문 바로가기
개발/React

👀 useRef란? #9

by 강누비 2024. 1. 10.
반응형

이번 포스팅은 useRef에 대해여 알아보도록 하겠다. 

 

useRef를 사용하는 때는 컴포넌트의 일부의 정보를 저장하고 싶지만, 해당 정보가 업데이트되더라도 렌더링이 되지 않도록 할때 useRef를 사용한다. 

 

이전에는 컴포넌트의 정보는 state를 통해서 저장하여 사용하는 방법을 사용하였다. 하지만 ref는 동일하게 컴포넌트의 정보를 저장하는 데 사용된다. stateref의 차이점에 대해서 살펴보겠다.

 

◼ State와 Ref의 차이점

ref state
useRef(initialValue)는 '{current : initialValue}'를 반환한다. useState(initialValue)는 state와 set인 [value, setValue]를 반환한다.
값을 변경하여도 리렌더 되지 않는다. 값을 변경하면 리렌더 된다.
Matable(가변객체)하다. Immutable(불변객체)하다.

 

간단하게 useRef와 useState를 차이점을 볼수있도록 구현한 코드를 살펴보겠다. state와 ref의 차이점에서 언급했던 것과 같이 StateCounter는 렌더링 되는 것을 확인할 수 있으며, RefCounter는 렌더링 되지 않는 것을 확인할 수 있다.

 

 

 

◼useRef의 활용

useRef를 일반적으로 사용하는 곳은 DOM Element를 접근할때 사용된다. React는 렌더링된 결과물에 따라 DOM를 변경을 자동으로 처리한다. 그렇기 때문에 컴포넌트에서 DOM을 조작할 필요가 없다. 하지만 용도에 따라 포커스를 옮기거나 스크롤 위치를 옮기며, 위치와 크기를 측정해야 할 때는 React가 관리하는 DOM요소에 접근해야 할 필요가 있다. 이때 DOM노드에 접근하기 위하여 useRef를 사용한다.

 

1. useRef 구조

useRef는 아래의 구조와 같다. 파라미터로는 initialValue를 받으며 반환값은 단일 Property를 갖은 객체인 '{current : initialValue}'를 반환한다.

useRef 구조

 

 

2. useRef의 역할

useRef의 역할으로는 값 참조 DOM 조작이 있다.

 

먼저 값을 참조하는 방법에 대하여 Interval을 활용한 예로 살펴보자.. useRef를 통하여 setInterval을 반환하는 Interval ID를 저장하여 원하는 때에 등록된 Interval를 취소하는 코드를 작성해 보도록 하자.

 

먼저 setInterval()의 반환값을 받아 변수에 저장한다. ref값을 변경하기 위해서는 current를 직접 변경해줘야 하므로 ref인 intervalRef의 단일 Property값인 current에 해당 Interval ID정보를 저장한다. 

function handleStartClick() {
  const intervalId = setInterval(() => {
    // ...
  }, 1000);
  intervalRef.current = intervalId;
}

 

그리고 나중에 아래와 값이 intervalRef에 저장되어 있는 Interval ID값을 읽어 Interval을 취소할 수 있다.

function handleStopClick() {
  const intervalId = intervalRef.current;
  clearInterval(intervalId);
}

 

 

아래는 위의 코드를 활용하여 작성한 useRef의 값을 참조하는 예제 코드이다.

 

다음으로는 DOM 조작이다.

 

React가 관리하는 DOM요소에 접근하기 위하여 useRef를 사용한다. 사용하는 방법으로는 간단하게 아래의 코드와 같다. DOM요소에 접근하기 위한 태그에 ref속성에 useRef()의 반환값을 넣어주면 myRef.current를 통하여 해당 div의 DOM요소에 접근할 수 있다.

 

function Test(){
	const myRef = useRef(null);
	//...
    
    // div의 DOM의 scroll을 정보
    myRef.current.scrollIntoView();
    
	return <div ref={myRef} />;
}

 

ref의 경우 Callback을 활용하여 ref를 다양한 컬렉션에 넣어 저장할 수 있다. 아래와 같이 catList를 바탕으로 map()을 활용하는 코드에서 li태그의 ref의 Callback 활용하여 li의 DOM노드를 itemsRef의 Map객체저장한다. Map에 저장된 li 태그의 DOM노드를 활용하여 Delet, Focus 등으로 활용한다.

   function Table(){
   
    const itemsRef = useRef(new Map());
    
    const catList = [];
    for (let i = 0; i < 10; i++) {
      catList.push({
        id: i,
        imageUrl: 'https://placekitten.com/250/200?image=' + i
      });
    }
    
    return (
            <ul>
              {catList.map(cat => (
                <li
                  key={cat.id}
                  ref={(node) => {
                  // node에 해당 'li'의 ref에 DOM정보가 있다.

                   const map = itemsRef.current;
                    if (node) {
                      map.set(cat.id, node);
                    } else {
                      map.delete(cat.id);
                    }
                  }}
                >
                  <img
                    src={cat.imageUrl}
                    alt={'Cat #' + cat.id}
                  />
                </li>
              ))}
            </ul>
        )
    }

 

 

간단한 useRef()를 활용한 DOM 조작의 예시를 살펴보자. inputRef를 input 태그의 DOM관리하며 button을 클릭 시 inputRef를 활용하여 input의 포커싱을 잡아준다.

 

3. useRef 사용 시 주의할 점 

DOM을 직접 변경했을 때 React는 DOM노드를 올바르게 관리하는 방법을 모른다. 아래의 예는 state와 ref에를 활용하여 작성한 코드이다. state의 상태에 따라 p 태그를 출력한다. ref의 remove()로 DOM을 삭제할 경우 state에 따라 출력해야 할 DOM까지 삭제되어 충돌이 발생한다. 이와 같이 React가 관리하는 DOM요소에 대하여 수정 삭제, 혹은 자식 추가일관적인 렌더링 결과를 보여주지 않을 수 있다.

 

그렇기 때문에 DOM요소에 대하여 조작하는 행동이 필요할 경우 React가 변경할 이유가 없는 부분을 수정하며, 포커싱, 스크롤링 DOM 요소의 크기 혹은 위치 측정 등과 같이 역할에 사용한다.

반응형

'개발 > React' 카테고리의 다른 글

👀 useContext란? #8  (0) 2024.01.06
👀 useReducer란? #7  (2) 2024.01.05
👀 State 변수 초기화 및 보존 #6  (0) 2024.01.04
👀 컴포넌트 렌더링 과정 #5  (2) 2024.01.03
👀 useState란? #4  (0) 2023.12.23