-
221220 TIL(useRef)하루 30분 TIL 2022. 12. 20. 21:20
useRef를 어떨 때 쓸까?
0. useRef로 특정 DOM 선택
- 특정 엘리먼트의 크기, 스크롤바 위치 혹은 포커를 설정해줘야 한다던지 DOM을 직접 선택해야 하는 상황
- D3, chart.js 같은 외부 라이브러리 사용할 때에도 특정 DOM에다 적용하기 때문에 DOM을 선택해야 하는 상황 발생
1. useRef를 활용한 리렌더링 방지input에 이름을 입력한 후 제출 버튼 클릭 시 입력된 이름 상태가 문장에 추가되도록 코르를 작성한다고 하자.
useState을 사용한다면 아래와 같이 사용할 것이다.
import React, { useState } from "react" function App() { const [name, setName] = useState("") const [currentName, setCurrentName] = useState("") console.log("render") return ( <> <input value={name} onChange={e => setName(e.target.value)} /> <button onClick={() => setCurrentName(name)}>제출</button> <div>나의 이름은 {currentName} 입니다.</div> </> ) } export default App
이때 콘솔 로그로 렌더링을 확인했을 때 입력할 때마다 렌더링이 일어나는 것을 알 수 있다.
렌더링을 통한 가시성 변화를 주는 작업이 아닐 때 굳이 useState을 통한 렌더링을 할 필요가 없다.
이때 useRef를 활용하여 렌더링을 방지할 수 있다.
import React, { useState, useRef } from "react" function App() { const [currentName, setCurrentName] = useState("") const inputRef = useRef("") console.log("render") return ( <> <input ref={inputRef} /> <button onClick={() => setCurrentName(inputRef.current.value)}>제출</button> <div>나의 이름은 {currentName} 입니다.</div> </> ) } export default App
마지막 div인 currentName의 경우 가시성이 필요하기 때문에 useState을 활용해 상태를 관리하지만
input의 경우 굳이 렌더링이 필요없다.
2. 다시 렌더링 되어도 동일한 참조값을 유지하고 싶을 때
1번과 같은 맥락이긴 하지만 아래의 조건을 만족하는 코드를 짠다고 생각해보자
"숫자가 mount될 때 0부터 차례로 증가, unmount될 때 현재 화면의 숫자를 alert 해준다."
useState을 활용해 아래의 코드를 작성해보면 어떻게 될까?
import React, {useEffect, useState} from 'react'; const Counter = () => { const [counter, setCounter] = useState(0); useEffect(() => { const timer = setInterval(() => { setCounter(prev => prev + 1); }, 1000); return () => { clearInterval(timer); alert(counter); }; },[]); return ( <div> <p>{counter}</p> </div> ); }; export default Counter;
alert창에 띄어진 counter의 값은 항상 0을 바라보고 있는 것을 알 수 있다.
그 이유는 setInterval 안의 setCounter로 인해 1초마다 렌더링이 일어나며 useEffect안의 counter값도 초기값인 0을 항상 바라보게 된다.
이때 사용할 useState 대신 useRef를 사용할 수 있다.
import React, {useEffect, useState, useRef} from 'react'; const Counter = () => { const [counter, setCounter] = useState(0); const unmountvisual = useRef(0); useEffect(() => { const timer = setInterval(() => { setCounter(prev => prev + 1); unmountvisual.current += 1; }, 1000); return () => { clearInterval(timer); alert(unmountvisual.current); }; },[]); return ( <div> <p>{counter}</p> </div> ); }; export default Counter;
위 코드로 작성 시 정상적으로 작동하는 것을 알 수 있다.
그 이유는 useRef를 통해 반환된 객체는 component의 생애주기 내내 변화하는 값을 가리키고 있기 때문입니다.
참고
https://react.vlpt.us/basic/10-useRef.html
https://medium.com/humanscape-tech/react-usestate-vs-useref-4c20713f7ef
https://velog.io/@kysung95/%EC%A7%A4%EB%A7%89%EA%B8%80-useRef%EA%B0%80-%EB%AD%94%EA%B0%80%EC%9A%94
'하루 30분 TIL' 카테고리의 다른 글
230113 30분 TIL forEach의 return (0) 2023.01.13 2301112 30분 TIL (a태그 noopener noreferrer / SOLID) (0) 2023.01.13 221214 TIL(useImperativeHandler) (0) 2022.12.14 221208 TIL(uncontrolled vs controlled) (0) 2022.12.09 221103 TIL (0) 2022.11.04