My Boundary As Much As I Experienced

React) useRef란? 본문

FrontEnd/React

React) useRef란?

Bumang 2023. 10. 22. 20:07

기존 useState를 쓸 때 발생하는 문제

아래는 리액트로 양방향 입력 컴포넌트를 만드는 흔한 예시이다.

양방향이란, 1. 유저가 input 태그에 입력해서 state값을 바꿀 수 있고, 2. 시스템이 다른 handler함수에서 setState를 통해 렌더된 인풋을 바꿀 수 있음을 의미한다.

const [state, setState] = useState(””)
<input onChange={(e)⇒ setState(e.target.value)} value={state} />

이게 틀리다는 건 아닌데 이런 식으로 하면 state가 바뀔 때마다 input이 재렌더 된다.

value={state}때문에 state값의 변화에 영향을 받는 이 input컴포넌트는 엄청나게 많은 재렌더 api를 쏘게 되는데..

(단순 키보드 입력 때마다 state가 바뀌기 때문. state가 쓰이는 모든 곳이 재렌더 된다.)

성능적으로 민감한 앱인 경우엔 이게 달갑진 않을 것이다.

 

 

useRef로 해결?

useRef는 위 문제점에 대한 대안이 될 수 있는 기능이다. 일단 기능을 설명하자면

useRef는 사실 기존 바닐라 스크립트의 DOM조작과 비슷한 기능을 수행해주는 기능이다.

// 바닐라 자바스크립트의 태그 선택자
document.querySelector("input")
//이거랑 비슷하다.


// 리액트의 useRef
const inputRef = useRef()
...
return <input ref={inputRef}>...</input>

 

useRef는 그저 해당 DOM요소를 타겟팅하고 있는거지 값이 바뀐다고 그 즉시 재렌더하지는 않는다. (useState와는 다르게...)

즉, 해당 태그의 값 조작은 필요할 때만 할 수 있다는 것이 장점이다.

 

그러므로 실제 값이 많이 바뀌지만, 이걸 일일이 재렌더를 할 필요가 없는 input에 useRef를 쓰면 된다.

(딱 필요할 때에만 재렌더를 걸면, 지금까지 바뀌어온 입력값이 재렌더 된다.)

 

 

 

주의할 점

그러나 이렇게 직접적인 DOM조작스러운 사용방식 때문에 안 좋아하는 사람들도 꽤 있다.

리액트의 데이터들은 props를 기반으로 움직이는데 useRef로 조작하는 것은 이 흐름에 독립적으로 발생하는 것이기 때문에,

너무 혼합해서 쓰다보면 헷갈릴 수 있을 것이다. (또한 거의 다 useRef로만 조작할거면 그냥 바닐라 자바스크립트 쓰는게 나을 것이다...)

 

 

그 밖에 useRef로 할 수 있는 것들

자동 포커스: 페이지 이동 후, 혹은 어떤 특정 이벤트 후 input에 자동 포커스가 걸리는 경우가 있는데, 리액트에서 state만으로 이걸 구현하기가 쉽지 않다. 이럴 땐 useRef를 사용해서 '자동 포커스 기계...'로 사용하는 경우도 있다.

 

 

 

useRef 사용 방법

일반적인 자바스크립트에서 변수를 만드는 것처럼 선언하면 된다. 이때 우측엔 useRef()를 넣으면 된다.

이 괄호에 넣는 값들은 ref안의 current라는 속성으로 관리된다.

즉 아무것도 안 넣으면 아래와 같은 형태인 것이다.

ref = {
  current: undefined
}

선언할 때 숫자, 문자열, 불린 모두 넣을 수 있는데, 그러면 ref의 current값은 이 값으로 초기화된다. (그럴 필요가 전혀 없지만..)

 

이때 리턴 부분의 원하는 태그에다 ref속성을 넣으면, ref변수의 current에 객체화된 HTMLElement가 반환된다.

ref = {
  current: HTMLInputElement {...}
}

 

그러면 이제 happy하게 원하는 만큼 돔조작을 해서 값을 조정하거나 말거나 하면 된다. 끝.

(인풋 태그에 걸고 그 값에 접근한다고 치면 inputRef.current.value를 사용하면 된다.)

// useRef를 선언한다.
const inputRef = useRef()

// 원하는 태그에다 ref={ref이름}을 넣는다.
<input ref={inputRef}>

// 만약 커스텀 컴포넌트에서 값을 받아야 된다면 리프팅 함수를 전달해서 아래 식으로 받아오면 된다.
const submitHandler = () ⇒ { props.onLifting( inputRef.current.value ) }

 

 

요약

리액트버전 document.getElementById(”html-id”)이다. 

getElementById(”html-id”) 대신 JSX의 해당 태그에 ref={inputRef}를 넣어
어떤 태그의 DOM요소를 반환받을건지를 명시한다.

재렌더를 발생시키지 않지만, DOM요소에 접근해서 원할 때 값을 참조해올 수 있는 것이다.

useRef로 관리되는 컴포넌트는 ‘제어되지않는 컴포넌트’라고 한다.
useRef의 반환된 컴포넌트는 리액트 컴포넌트의 전생애주기에도 유지가 된다.

 

'FrontEnd > React' 카테고리의 다른 글

React) useContext 사용법  (0) 2023.10.23
React) useReducer란?  (0) 2023.10.23
React) 리액트 포털(React Portal)  (0) 2023.10.22
React) JSX가 처리되는 과정  (1) 2023.10.22
React) 메모이제이션  (0) 2023.10.17