[짤막글] useRef가 뭔가요?

kysung95·2021년 4월 15일
11

짤막글

목록 보기
5/15
post-thumbnail

안녕하세요. 김용성입니다.
오늘은 useRef hook에 대해 간단히 알아보는 시간을 가지도록 하겠습니다.

우리가 vanilla javascript를 사용할 때 특정 DOM에 접근하고 싶다면 queryselector이나 getElementId를 활용하잖아요. react에서 이러한 것들을 가능하게 해주는 것이 useRef라고 생각하시면 돼요. 정말 쉽죠? 그럼 오늘 포스팅은 여기서 끝내겠습니다.

라고 하면 너무 영양가가 없죠? useRef를 다루는 것과 useRef의 편리한 기능으로 인해 useState에 대해서도 설명드리도록 할거예요 ㅎㅎ

useRef의 편리성

우리가 react로 프로젝트를 진행하다보면 컴포넌트 별로, 요소 별로 특정 값(데이터)를 갖게 하고 싶을 때가 있습니다. 컴포넌트 별로 데이터를 갖고 싶을 때가 있습니다. 대개의 경우 이럴 때 useState를 사용하죠. 그렇지만 제가 앞서 useMemo와 useCallback 관련하여 포스팅한 글을 보다보면 제가 정말 강조했던 부분이 있어요.

  • 함수형 컴포넌트는 그냥 함수입니다. 다시 한 번 강조하자면 함수형 컴포넌트는 단지 jsx를 반환하는 함수이죠.
  • 컴포넌트가 렌더링 된다는 것은 누군가가 그 함수(컴포넌트)를 호출하여서 실행되는 것을 말합니다. 함수가 실행될 때마다 내부에 선언되어 있던 표현식(변수, 또다른 함수 등)도 매번 다시 선언되어 사용됩니다.
  • 컴포넌트는 자신의 state가 변경되거나, 부모에게서 받는 props가 변경되었을 때마다 리렌더링 됩니다. 심지어 하위 컴포넌트에 최적화 설정을 해주지 않으면 부모에게서 받는 props가 변경되지 않았더라도 리렌더링 되는게 기본입니다.

바로 위에 언급한 react의 기본적인 특성들인데요. useState는 데이터를 저장하지만, state가 바뀔 때마다 컴포넌트가 리렌더링 된다는 단점을 지니고 있습니다.
만약 우리가 컴포넌트 별로 특정 데이터를 가지게 하고, 이러한 데이터들을 리렌더링 없이 관리하고 싶다면 useRef를 사용한다면 가능합니다.

우선 useRef의 기본적인 사용 사례부터 확인해보겠습니다.

useRef 기본 활용

const refContainer = useRef(initialValue);

react 공식 홈페이지에서 제공하는 useRef 사용법입니다.

이제 사용상황을 가정해볼까요?

우리가 커뮤니티 서비스를 만들고 있습니다. 커뮤니티의 디테일 페이지에서 "댓글달기" 라는 버튼을 클릭하였을 때, 우리의 마우스 커서가 댓글을 입력하는 input창에 focus되었으면 좋겠다는 생각을 하겠죠? 그럴때 useRef를 활용하면 됩니다.

import React, { useState, useEffect, useRef } from "react"

function App() {
  const [name, setName] = useState("")
  const inputRef = useRef("")

  console.log("render")

  const focus = () => {
    inputRef.current.focus()
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={focus}>focus</button>
    </>
  )
}

export default App

위의 코드처럼 input창을 useRef hook을 통해 inputRef라는 지정 DOM으로 설정해준 뒤,
inputRef.current.focus() 라는 focus 함수를 선언해준 뒤 button 태그의 클릭event로 넣어주면 됩니다.

current가 뭔가요???

Ref객체의 .current값은 선택한 DOM을 가리키게 됩니다. 현재 Ref 객체를 뜻하므로 해당 객체의 기능을 이용한다거나 값을 이용하는 경우에는 current를 반드시 붙여주어야 합니다. 또한 current의 default 값은 useRef를 통해 Ref 객체를 선언할 때 넣어주었던 argument 값이 된다는 점 알아두셔야 합니다. 위 코드에서는 ""라는 빈 값을 넣어줬습니다.

useRef는 상당히 많이 사용되므로 반드시 알아두시는 것이 좋아요. scroll 관련해서 animation을 가미하고 싶을 때에도 useRef를 사용하면 훨씬 간단하게 작업할 수 있답니다 :)

useRef로 리렌더링 방지

자 이번에는 ref를 통해 input 창에 입력되는 state 요소가 변경될때마다 렌더링 작업이 반복되는 것을 막아보도록 하겠습니다.

input에 이름을 입력한 후 제출 버튼을 누를 경우, 입력된 이름 상태가 문장에 추가되도록 코드를 작성해보았습니다. useState를 사용해서 말이죠.

코드를 살펴볼까요??

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

그냥 평범한 코드입니다. 그렇지만 이름을 입력할 때 해당 컴포넌트가 얼마나 리렌더링될까요?
제가 컴포넌트 내부에 console.log("render")을 넣어놨기 때문에 이를 직관적으로 확인할 수 있었습니다.

어마어마하게 렌더링이 많이 일어나네요..ㅎㅎ 굳이 이렇게 많은 리렌더링이 필요한 작업이 아니라는 점 여러분들도 아셨죠? 사실상 제출 버튼을 눌렀을 때만 rendering이 일어나면 되지 않나 하는 생각이 드시는 분들이 계실거예요.
저는 위 코드를 useRef를 사용하여 다음과 같이 변경해보았습니다.

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

inputRef.current.value를 통해 input에 있는 현재 value 값을 가져와서 제출하도록 하였습니다. 실행해보시면 알겠지만 컴포넌트 리렌더링이 현저히 줄어들었습니다. 줄어든게 아니라, input에서 setName함수를 실행시켜 해당 state값을 변경할 때마다 일어나던 rendering이 아예 사라졌기 때문에, 화면을 처음 받아올 때와 제출 버튼을 눌렀을 때만 rendring이 일어난다는 것을 알 수 있습니다.

불필요한 리렌더링 방지. useRef 정말 좋지 않나요?? ㅎㅅㅎ

마무리

오늘은 짧게 useRef가 어떤 녀석인지 살펴보았습니다. 조금 더 예제 코드를 넣어서 depth있는 포스팅을 하고싶었는데, 시간이 충분치 않네요. useRef를 기똥차게 사용하는 방법이 생각나면 추후에 추가적으로 포스팅 업데이트를 실시하겠습니다 ^^7
감사합니다:)

profile
김용성입니다.

0개의 댓글