useRef 사용방법

Han Lee·2024년 2월 5일

useRef는 새로운 렌더 작업을 수행하지 않고, 값을 참조할 수 있게 만들어주는 React Hook 이다.

P1. useRef

1. useRef

  • 컴포넌트가 어떤 정보를 "기억(Remeber)"하기를 원하지만, 해당 정보가 새로운 렌더링 트리거(Trigger)가 되지 않기를 원하는 경우 useRef 훅을 사용할 수 있다.

2. Trigger new Renders

(1) Render and Commit

  • 컴포넌트가 화면에 "표시(Displayed)"되기 전에, 컴포넌트는 반드시 React에 의해 "렌더(Render)"작업이 수행 되어야 한다.

  • 렌더(Render)단계란, 리액트가 컴포넌트를 렌더링하고 변경 사항을 계산하는 모든 작업을 말한다.

  • 주방에서 컴포넌트가 요리사가 되어 재료를 가지고 맛있는 음식을 조립한다고 상상하자.

  • 이 경우, 리액트는 웨이터로 고객의 요청사항을 입력하고 완성된 요리를 손임에게 가져다 줍니다.

  • UI를 요청하고 제공하는 프로세스는 다음 세가지 단계로 이루어 집니다.

(2) Proecess

  • React에서는 다음 3가지 단계에 따라 화면이 업데이트 됩니다.
  • React에서는 렌더링 결과 값이 이전과 동일(Same)한 경우, DOM을 수정하지 않습니다.

1단계 Triggering a render

  • 손님의 주문을 주방에 배달합니다.

2단계 Rendering the Component

  • 주방에서 주문에 따라 준비합니다.

3단계 Committing to the DOM

  • 손임 테이블에 준비된 음식을 가져다 드립니다.

Step 1: Trigger a Render

  • 컴포넌트는 다음 2가지 이유로 렌더링 된다.
  • ① 컴포넌트의 초기 렌더링
  • ② 컴포넌트(상위 컴포넌트)의 상태(State)가 업데이트된 경우

Step 1 - (1) Initial Render

  • 앱이 시작되면 초기 렌더링을 트리거해야 합니다.
  • 초기 렌더링은 Target DOM Node와 함께 createRoot를 호출한 다음, Component(구성요소)를 인수로 하여 Render 메서드가 호출된다.
import Component from './Component.js';
import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'))
root.render(<Component />);

Step 1 - (2) Re-renders when state update

  • 컴포넌트가 성공적으로 초기 렌더링 된 이후에, "set function"함수를 호출하여
    상태(State)를 업데이트 함으로써 다음 렌더링을 트리거(Trigger)할 수 있습니다.
  • 상태(State)가 업데이트 된 컴포너넌트는 렌더링을 자동으로 대기합니다.
    ( 최초 주문 이후, 배고픈 상태에 따라 손님이 차, 디저트 등을 추가 주문하는 것을 상상할 수 있습니다. )

Step 2: React renders your Components

  • 렌더를 트리거(Trigger)한 후, React는 화면에 무엇을 표시해야 하는지 이해하기(figure out)위해 컴포넌트를 호출 합니다.
  • "Rendering"은 React가 Components를 호출하는 것입니다.

On initial render(초기 렌더링)에서, React는 Root Component를 호출합니다.
For Subsequent Renders(후속 렌더링)의 경우, React는 State가 업데이트되어 Render를 트리거(Trigger)하는 함수형 컴포넌트(Function Component)를 호출합니다.

  • This Process is recursive(재귀적) 입니다.
  • 업데이트된 Component가 다른 Component를 반환하면, React는 해당 컴포넌트의 다음 Component를 렌더링 합니다.

export default function Gallery() {
  return (
    <section>
      <h1>Inspiring Sculptures</h1>
      <Image />
      <Image />
      <Image />
    </section>
  );
}

function Image() {
  return (
    <img
      src="https://i.imgur.com/ZF6s192.jpg"
      alt="'Floralis Genérica' by Eduardo Catalano: a gigantic metallic flower sculpture with reflective petals"
    />
  );
}
  • During the initial render, 리액트는 section, h1, 그리고 3개의 미지 태그를 위한 DOM node를 생성합니다.
  • During a re-render, 리액트는 DOM node의 속성을 계산합니다. ( 만약에 이전 렌더로 부터 변경된 사항이 있다고 하더라고. )
    그리고 다음 단계인 Commit 단계 까지는 절대로 계산된 정보를 사용하지 않습니다.

▶ PitFall

  • Rendering은 반드시 항상 순수 함수(Pure Calculation)이여야 합니다.

  • Same inputs, same out.
    동일한 인수가 주어지면, Component는 항상 동일한 JSX를 반환해야 합니다.
    ( 토마토가 들어간 샐러드를 주문했는데, 양파가 들어간 샐러드를 받아서는 안됩니다. )

  • 자신의 상태에 주의를 다합니다.
    렌더링 이전에 존재했던 객체나 변수를 변경해서는 안됩니다.
    ( 하나의 주문이 다른 누군가의 주문을 변경해서는 안됩니다. )

Step 3: React commits changes to the DOM

After rendering(calling) your components, React는 DOM을 수정합니다.

  • For the initial render
    Initial 렌더의 경우, React는 appendChild() DOM API 사용하여, 생성한 모든 DOM 노드를 화면에 표시합니다.

  • For re-render
    Re 렌더의 경우, React는 DOM이 가장 최근의 렌더링 결과물과 일치하도록 필요한 최소한의 작업(렌더링 중 계산된)을 적용(Apply)합니다.

  • React only changes the DOM nodes if there's a difference between renders.

  • 매초마다 부모로 부터 props를 전달받아 Re-Render 되는 컴포넌트가 있다.
  • 여기서 주목할 점은 input tag로, 컴포넌트가 매초 Re-Render될 때마다 업데이트한 value(text)가 사라지지 않는 것을 볼 수 있다.
  • 왜냐하면, React는 오로지 새로운 props로 전달된 state(time)만을 Re-Render하여 h1 tag 만을, 해당 DOM Element만을 업데이트하기 때문이다.

React Render Phase vs Commit Phase

Epilogue: Browser paint

  • 렌더링(Rendering)과 React가 DOM을 업데이트하면, 브라우저가 화면을 다시
    re-paint 합니다.
  • 이러한 프로세스를 "브라우저 렌더링"이라고 하지만, 문서 전체의 혼란을 주지 않기 위해 "페인팅"이라고 부릅니다.

P2. useRef 사용 방법

1. Adding a ref

(1) Secret Pocket

  • Component 안에서 useRef 호출하고, 참조하기를 원하는 값(value)에 대한 초깃값을 설정하면 된다.
const ref = useRef(0)
  • useRef는 current 속성을 가진 객체(object)를 반환한다.
{ 
  current: 0 // The value you passed to useRef
}

  • ref.current 속성을 사용해 ref의 현재 값에 접근(access)할 수 있습니다.
  • 해당 값은 의도적으로 변경 가능("Mutable")하기 때문에, 개발자는 해당 값을 읽고(read) and 쓸수(write) 있습니다.
  • REF는 컴포넌트 안에 있는 비밀 주머니 이기 때문에, react는 해당 값을 추적할 수 없습니다.
    ( 이것은 React의 일방적인 데이터 흐름[One-Way Data Flow] "탈출구(Escape hatch)" 입니다. )

2. Example

(1) Example - Only useRef

  • useRef 사용하여 무엇이든 참조할 수 있다. (Ex string, object, function ).
  • state와 달리, ref는 current 속성을 갖고 있는 "Plain JavaScript Object"이기 때문에 개발자는 읽고, 수정할 수 있다.
  • 즉, state의 경우, Component를 Re-Render를 수반하지만, ref의 경우 Re-Render를 수반하지 않습니다.

(2) Example - Both useState and useRef

  • 개발자는 Refs와 State를 하나의 컴포넌트 안에서 조합하여 사용할 수 있다.
  • "start" or "stop" 버튼을 사용해 Stopwatch 만들 수 있다.

P3. useRef 사용 방법 with DOM

https://react.dev/learn/manipulating-the-dom-with-refs

0개의 댓글