TypeScript 12장 - useRef 사용하기
포스트
취소

TypeScript 12장 - useRef 사용하기

TypeScript

useRef

useRef 공식문서

  • React hook의 일종으로, 인자로 넘어온 초깃값을 useRef객체의 .current 프로퍼티에 저장한다.
  • DOM객체를 직접 가리킬 때나, 값이 변경되어도 컴포넌트가 리렌링되지 않도록 하기 위해 값들을 저장할 때도 사용한다.
  • .current를 변경시키는 것은 리렌더링을 발생시키지 않기 때문에 로컬 변수 용도로도 사용할 수 있다.

타입 에러

참고자료 1 참고자료 2

  • 미니 프로젝트를 만들던 중 useRef에 대한 타입에러가 발생했다.
  • 검색어를 입력하는 input을 만들고, 그 옆에 검색 아이콘 버튼을 만들어서, 엔터를 쳤을 때나 아이콘을 클릭했을 때 검색어가 저장되게 해주고 싶었다.
  • useRef를 사용해서 input에 입력된 현재값을 가져오고 싶었는데 input props type error가 발생했다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function Example(){
    const [keyword, setKeyword] = useState("");

    const inputRef = useRef();

    const keywordHandler: ComponentProps<"input">["onKeyPress"] = (e) => {
    if (e.key === "Enter") {
      const inputElement = e.target as HTMLInputElement;
      setKeyword(inputElement.value);
    }
  };

  const iconClickHandler: ComponentProps<"svg">["onClick"] = () => {
    const inputValue = inputRef.current.value;
    setKeyword(inputValue);
  }

  return (
    <React.Fragment>
        <InputEle onKeypress={keywordHandler} {/*에러 부분*/} ref={inputRef}/>
        <AiFillSearch onClick={}>
    </React.Fragment>
  )
}
1
2
3
4
5
'MutableRefObject<HTMLInputElement | null | undefined>' 형식은 'LegacyRef<HTMLInputElement> | undefined' 형식에 할당할 수 없습니다.
'MutableRefObject<HTMLInputElement | null | undefined>' 형식은 'RefObject<HTMLInputElement>' 형식에 할당할 수 없습니다.
'current' 속성의 형식이 호환되지 않습니다.
'HTMLInputElement | null | undefined' 형식은 'HTMLInputElement | null' 형식에 할당할 수 없습니다.
'undefined' 형식은 'HTMLInputElement | null' 형식에 할당할 수 없습니다.

해결 방법

  • useRef에 초깃값을 null로 설정해주면 간단하게 해결할 수 있다.
1
const inputRef = useRef(null);

원인

  • useRefctrl + 클릭으로 타입을 확인해보면 3가지 타입을 확인할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
function useRef<T>(initialValue: T): MutableRefObject<T>;
function useRef<T>(initialValue: T | null): RefObject<T>;
function useRef<T = undefined>(): MutableRefObject<T | undefined>;

interface MutableRefObject<T> {
        current: T;
}

interface RefObject<T> {
        readonly current: T | null;
    }
  • 설명에 대한 경우의 수는 다음과 같다.
    1. useRef에 입력될 인자의 타입과 제네릭 타입이 일치할 경우,MutableRefObject<T>
    2. useRef에 입력될 인자의 타입이 null을 허용한 경우,RefObject<T
    3. useRef에 입력될 제네릭 타입이 undefined인 경우,MutableRefObject<T | undefined>
  • 각 경우의 수에 해당하는 MutableRefObject, RefObject를 보면 MutableRefObject초깃값을 current에 저장하는 반면, RefObject의 값은 읽기 전용으로 되어 있다.
  • MutableRefObject는 current 값을 변경할 수 있고, RefObject의 current 값은 변경될 수 없다.

예시 1.

  • 버튼을 클릭하여 값을 증가시키는 코드이다.
  • current를 직접 변경시킬 수 있는 이유는, useRef초기 인자를 입력한 1번의 경우에 해당한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React, { useRef } from "react";

function App() {
  const localVarRef = useRef<number>(0);

  const handleButtonClick = () => {
    if (localVarRef.current) {
      localVarRef.current += 1;
      console.log(localVarRef.current);
    }
  };

  return (
    <div className="App">
      <button onClick={handleButtonClick}>+1</button>
    </div>
  );
}

export default App;

예시 2.

  • 만약 초기 인자로 null을 넘겨주면, 2번 경우에 해당되기 때문에 currrent에 에러가 발생하게 된다.
1
2
3
4
5
6
const localVarRef = useRef<number>(null);

const handleButtonClick = () => {
  localVarRef.current += 1;
  console.log(localVarRef.current); // 에러발생
};
1
2
React.RefObject<number>.current : number | null
Cannot assign to 'current' because it is a read-only property.

예시 3.

  • 만약 버튼을 클릭하여 current의 value값을 변경하고자 할 때, 초깃값을 null로 지정했을 때의 예시이다.
  • 초깃값을 null로 넘겨줬으니 2번의 경우에 해당하지만 value 값을 변경할 수 있는데, 이는 cuurent 프로퍼티만 읽기 전용으로 하위 프로퍼티인 value 는 수정이 가능하기 때문이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { useRef } from "react";

function App() {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleButtonClick = () => {
    if (inputRef.current) {
      inputRef.current.value = "";
    }
  };

  return (
    <div className="App">
      <button onClick={handleButtonClick}>+1</button>

      <input ref={inputRef} />
      <button onClick={handleButtonClick}>Clear</button>
    </div>
  );
}

export default App;

예시 4.

  • 그럼 useRef의 인자를 undefined로 바꿀 경우를 봐보자.
  • 에러 메시지를 보면 MutableRefObject형식은 RefObject 형식에 할당할 수 없다는 메시지를 볼 수 있다.
1
const inputRef = useRef<HTMLInputElement>();
1
2
3
4
5
6
'MutableRefObject<HTMLInputElement | undefined>' 형식은 'RefObject<HTMLInputElement>' 형식에 할당할 수 없습니다.
'current' 속성의 형식이 호환되지 않습니다.
'HTMLInputElement | undefined' 형식은 'HTMLInputElement | null' 형식에 할당할 수 없습니다.
'undefined' 형식은 'HTMLInputElement | null' 형식에 할당할 수 없습니다.
오버로드 2/2('(props: FastOmit<DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, never>): ReactElement<...> | null')에서 다음 오류가 발생했습니다.
'MutableRefObject<HTMLInputElement | undefined>' 형식은 'LegacyRef<HTMLInputElement> | undefined' 형식에 할당할 수 없습니다.ts(2769)

2024-03-11

  • next.js에서 사용할 경우, useRef는 브라우저 환경에서 사용되는 훅이기에 use client를 작성해주어야 한다.
  • useEffect와 같이, 서버와 클라이언트에서 모두 동작할 수 있는 훅이 있는 반면에, useRef는 직접적으로 DOM에 접근하는만큼 서버 환경에서 사용할 수 없거나 예기치 않은 동작을 발생시킬 수 있다.
  • 따라서 클라이언트 컴포넌트로 동작하도록 명시해주어야 한다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.