JSX로 구성된 유튜브 토이 프로젝트를, TSX로 변경하는 과정에서
useRef
관련 이슈를 해결하며 새로 알게된 내용을 간단히 정리해보았다.
function SearchBar({ onSearch, onLogoClick }) { const inputRef = useRef(); const handleSearch = () => { const { value } = inputRef.current; onSearch(value); }; const onKeyPress = (e) => { if (event.code === "Enter") { handleSearch(); } }; return ( <StyledContainer> <StyledInput type="search" placeholder="Search..." onKeyPress={onKeyPress} ref={inputRef} /> </StyledContainer> ); }
useRef
관련 로직에 TSX를 적용하면서 찾아보니 React TypeScript Cheatsheets에 useRef
관련 내용들이 있었다.In TypeScript,
useRef
returns a reference that is eitherread-only
ormutable
, depends on whether your type argument fully covers the initial value or not. Choose one that suits your use case.To access a DOM element: provide only the element type as argument, and use
null
as initial value. In this case, the returned reference will have aread-only
.current that is managed by React. TypeScript expects you to give this ref to an element's ref prop:
If you are sure that divRef.current will never be null, it is also possible to use the non-null assertion operator !:
const divRef = useRef<HTMLDivElement>(null!); // Later... No need to check if it is null doSomethingWith(divRef.current);
useRef
를 통해 DOM element
에 접근할 때, 초깃값을 포함하는지 여부에 따라서 useRef
가 read-only
거나 mutable
참조를 반환한다고 되어있다. (RefObject<HTMLDivElement>
을 리턴)
DOM element
에 접근하기 위해서는 초깃값을 null
로 지정해주면 read-only
를 반환할 수 있다고 나와 있다. 따라서 다음과 같이 수정할 수 있었으며 추가로 ref
의 타겟이 되는 input
태그의 value
는 null
이 아니기 때문에 Non-null assertion operator
인 !
를 사용하여 non-null
체크를 해주었다.
function SearchBar({ onSearch, onLogoClick }: INavEventHandler): JSX.Element { const inputRef = useRef<HTMLInputElement>(null!); const handleSearch = () => { const { value } = inputRef.current; onSearch(value); }; const onKeyPress = (e:React.KeyboardEvent) => { if (e.code === "Enter") { handleSearch(); } }; return ( <StyledContainer> <StyledInput type="search" placeholder="Search..." onKeyPress={onKeyPress} ref={inputRef} /> </StyledContainer> ); }
function Foo() { // Technical-wise, this returns MutableRefObject<number | null> const intervalRef = useRef<number | null>(null); // You manage the ref yourself (that's why it's called MutableRefObject!) useEffect(() => { intervalRef.current = setInterval(...); return () => clearInterval(intervalRef.current); }, []); // The ref is not passed to any element's "ref" prop return <button onClick={/* clearInterval the ref */}>Cancel timer</button>; }
DOM element
에 접근하는 것이 아닌, 동적인 값(number
, string
등)을 useRef
로 지정할 경우 초깃값을 null
로 지정하며 MutableRefObject<number | null>
을 리턴하기 때문에 타입 또한 <number | null>
로 지정해준다.