해당 글의 자료와 코드는 여기를 바탕으로 다시 정리해본 글입니다
TS2322: Type 'MutableRefObject' is not assignable to type '((instance: HTMLInputElement | null) => void) | RefObject | null | undefined'.
Type 'MutableRefObject' is not assignable to type 'RefObject'.
Types of property 'current' are incompatible.
Type 'undefined' is not assignable to type 'HTMLInputElement | null'.
해당 링크는 여기를 클릭하면 확인가능합니다.
const SignUp = () => {
const emailRef = useRef();
const passwordRef = useRef();
const passwordConfirmRef = useRef();
return (
<>
...중략...
<Form.Control type="email" ref={emailRef} required />
...중략...
<Form.Control type="password" ref={passwordRef} required />
...중략...
<Form.Control type="password" ref={passwordConfirmRef} required />
...중략...
</>
);
};
useRef를 이용해 변수(emailRef, passwordRef, passwordConfirmRef)를 정의하고,
사용하려는 엘리먼트에 ref를 지정했습니다.
각각의 변수(emailRef, passwordRef, passwordConfirmRef)에 input의 값을 저장하려고 했습니다.
const emailRef = useRef<HTMLInputElement>(null);
const passwordRef = useRef<HTMLInputElement>(null);
const passwordConfirmRef = useRef<HTMLInputElement>(null);
const 변수명 = useRef<ref를 지정한 html 엘리먼트>(초깃값으로 설정할 값(예: 숫자,null,string..));
const localValRef = useRef<number>(숫자)
const emailRef = useRef<HTMLInputElement>(null)
MutableRefObject : 변경이 가능한 객체
RefObject : 읽기전용, 즉 변경이 불가능한 객체
=> 변수, 즉 값으로서 관심있을 때는, Mutation 객체를 반환해야한다.
=> Mutation이 아닌, 참조 목적이라면 RefObject를 반환해야한다.
4-1 : 타입 과 인자가 "서로 같은 타입"인 경우,
const localValRef = useRef<number>(0)
=> useRef에 할당한 타입(T)과 동일한 타입의 객체를 얻을 수 있다. 여기서 number을 할당했으므로 localValRef는 숫자타입니다.
4-2 : 인자에 null을 허용하는 타입(T|null)을 할당할 경우,
RefObject를 반환한다. 위의 A경우와 달리 값은 readonly이므로 수정 불가능하다.
4-3 : 인자가 undefined 일 경우,
useRef는 MutableRefObject<T | undefined>를 반환한다.
useRef<T>(initialValue: T): MutableRefObject<T>;
useRef<T>(initialValue: T|null): RefObject<T>;
useRef<T = undefined>(): MutableRefObject<T | undefined>;
interface MutableRefObject<T> {
current: T;
}
interface RefObject<T> {
readonly current: T | null;
}
useRef를 변수로 사용할 때, 초깃값은 .current에 저장됩니다.
다음처럼 쓰면 된다.
const localVarRef = useRef<number>(0)
case1은 다음의 정의를 따른다.
useRef<T>(initialValue: T): MutableRefObject<T>;
interface MutableRefObject<T> {
current: T;
}
[해석]
useRef우측, <>안에 들어가는 타입(T)과 inititialValue의 타입(T)가 서로 같으면,
MutabelRefObject가 반환되는데, 이때 같은 타입(T)으로 적용됩니다.
이때, useRef는 MutableRefobject 인터페이스를 따르는데, MutableRefobject의 타입으로 된 타입이 current의 타입(T)이 된다.
즉, useRef의 타입과 initialValue의 타입이 서로 일치하면, current도 동일하게 같은 타입(T)을 받게 됩니다.
const localVarRef = useRef<number>(0)일 경우,
useRef의 타입과 initialValue가 number타입이 되기 때문에 localVarRef는 number타입이 된다.
이때, MutationObjectRef가 반환하며, 이름처럼 Mutation, 즉 변경가능한 값이다.
다음처럼 작성하면 됩니다.
const localVarRef = useRef<number>(0);
const localVarRef = useRef<여기>(저기);
'여기'와 '저기'의 타입(예:number,string,boolean..)이 서로 같은 경우, current의 값을 변경하며 사용할 수 있다.
const localVarRef = useRef<number>(0);
0 과 number는 서로 타입이 일치함,
즉, useRef의 인자( )타입과 제네릭타입< >이 서로 일치 할 경우, MutableRefObject이 반환되어 값을 변경(Mutation)할 수 있다.
다음과 같은 경우,
const localVarRef = useRef<number>(0);
localVarRef는,
MutableRefObject<number> 타입이 된다.
그래서,
.current프로퍼티에 넣은 값을 수정해 사용할 수 있습니다.
: 버튼을 클릭할 경우 localVarRef.current의 값이 1씩 증가하는 코드 입니다.
import React, { useRef } from "react";
const 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;
다음처럼 쓰면 된다.
const emailRef = useRef<HTML엘리먼트객체>(null)
case2는 다음의 정의를 따른다.
useRef<T>(initialValue: T|null): RefObject<T>;
interface RefObject<T> {
readonly current: T | null;
}
해석
inititialValue에 T|null 값을 허용할 경우,
useRef우측 <>에 입력한 타입T의 RefObject를 반환합니다.
반환되는 값은 RefObject로 수정 할 수 없는(readonly) current 프로퍼티를 갖습니다.
: 버튼을 클릭하면 input의 value를 직접 빈 문자열로 수정하는 예제입니다.
import React, { useRef } from "react";
const 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;
그러나!
inputRef.current.value = "";
초깃값(initialValue)에 null값이 들어올 경우, 수정 불가능한 RefObject가 반한됩니다.
이것은 current의 값을 수정 불가능한(readonly)한데 어떻게 (current아래) value에 값을 수정할 수 있을까요?
이는 readonly가 shallow(얕은객체복사)이기 때문입니다.
current는 변경이 불가능하나, current아래 value는 변경가능합니다.