useRef

코와->코어·2022년 5월 21일
0

세미나 자료

목록 보기
6/7

createRef, useRef의 차이

특정 dom을 잡아야 할때 ref를 사용합니다. ref를 쓸 때, createRef와 useRef 두 방식으로 ref를 만들 수 있습니다.

class 컴포넌트

class형 컴포넌트에서는 아래와 같은 예제로 createRef를 통해 ref를 사용합니다.
class App extends React.Component {
componentDidMount() {
this.divRef = React.createRef();
}
render() {
return (

  <div>
    <div id="divR" ref={this.divRef}>
      App, here
    </div>
  </div>
);

}
}

함수형 컴포넌트

함수형 컴포넌트에서는 useRef를 사용합니다.
import React, { useRef } from "react";

const App = () => {
const divRef = React.useRef();
const valueRef = React.useRef(90);
return (

<div>
  값 : {valueRef.current}
  <div id="divR" ref={divRef}>
    App, here
  </div>
  <button onClick={() => (valueRef.current = 88)}> 증가 </button>
</div>

);
};

export default App;

위 코드를 실행하면 valueRef값이 88로 바뀌지 않는 다는 것을 알 수 있습니다.
만약 반응형으로 바뀌도록 의도한다면, 일부러 useState를 실행하면 됩니다.
import React, { useState, useRef } from "react";

const App = () => {
const divRef = React.useRef();
const valueRef = React.useRef(90);
const [, setState] = useState();
return (

<div>
  값 : {valueRef.current}
  <div id="divR" ref={divRef}>
    App, here
  </div>
  <button onClick={() => ((valueRef.current = 88), setState({}))}>
    증가
  </button>
</div>

);
};

export default App;

그러나 createRef를 함수형 컴포넌트에서 사용할 경우 문제점이 있습니다. 예를 들어 함수형 컴포넌트에서 createRef를 사용하면
import React, { useState, createRef } from "react";

const App = () => {
const valueRef = createRef();
const [, setState] = useState();
return (

<div>
  값 : {valueRef.current}
  <button onClick={() => ((valueRef.current = 88), setState({}))}>
    증가
  </button>
</div>

);
};

export default App;

렌더링의 문제는 없지만, 증가 버튼을 클릭해도 이전 과 같이 88로 바뀌지 않는 다는 것을 볼 수 있습니다.
이유는 App 컴포넌트가 setState에 의해 리렌더링 되면 App 컴포넌트를 초기화 하고 다시 만듭니다. 그에 따라 createRef도 다시 실행되는데, 이 때 createRef에 의해 만들어진 값은 무조건 null로 다시 초기화 됩니다.
react의 createRef 코드 (opens new window)를 참고하세요
그래서 함수혐 컴포넌트의 수명 내내 ref의 current 값을 유지하기 위해 useRef hook이 만들어진 것입니다.
useRef로 만들어진 값은 함수가 리렌더링 되어도 ref가 null로 초기화 되지 않습니다. (ref 값이 다시 재생성되지 않음)

결론

class형 컴포넌트에서 ref를 잡아야하는 경우 React.createRef를 사용한다.
함수형 컴포넌트의 경우 React.createRef와 React.useRef 둘다 사용가능 하지만 React.createRef를 사용할 경우 리렌더링 될때마다 ref 값이 초기화되어 원하는 값을 얻지 못할 것이다. 그러니 useRef를 사용한다.

Ref란?
특정 노드나 컴포넌트에 레퍼런스 값을 만들어주는 것입니다. 때문에 Ref를 통해서 노드나 리액트 요소에 접근하여 값을 얻어낼 수 있습니다.
레퍼런스를 만들기 위해선 리액트 내장함수인 createRef와 리액트 훅인 useRef() 가 있는데요. createRef는 클래스형 컴포넌트 useRef()는 함수형 컴포넌트에서 사용합니다.
먼저 클래스형 컴포넌트의 createRef의 코드를 살펴보겠습니다.
클래스형 컴포넌트 코드 살펴보기
import React, { useState } from "react";

import React, { Component } from "react";

class App extends Component {
state = {
text: [],
};

//레퍼런스를 만들기 위한 리액트 내장함수
//레퍼런스명 = React.createRef();
inputRef = React.createRef();
handleAddText = (e) => {
e.preventDefault();

//해당 레퍼런스(여기서는 input)의 현재 밸류값 가져오기
const newText = [this.inputRef.current.value, ...this.state.text];
this.setState({ text: newText });

};
render() {
return (

  <div>
    <form onSubmit={this.handleAddText}>
    
    //가져오고 싶은 요소에 레퍼런스 속성 및 레퍼런스명 지정
      <input ref={this.inputRef} />
      <button>버튼</button>
    </form>
    <ul>
      {this.state.text.map((item) => {
        return <li>{item}</li>;
      })}
    </ul>
  </div>
);

}
}
export default App;

함수형 컴포넌트 코드 살펴보기

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

function App() {
const [text, setText] = useState([]);
const inputRef = useRef();
const handleAddText = (e) => {
e.preventDefault();
setText([inputRef.current.value, ...text]);
};

return (

<div>
  <form onSubmit={handleAddText}>
    <input ref={inputRef} />
    <button>버튼</button>
  </form>
  <ul>
    {text.map((item) => {
      return <li>{item}</li>;
    })}
  </ul>
</div>

);
}

export default App;

이런식으로 같은 결과물인 클래스형과 함수형 컴포넌트 각자의 코드를 구성해보았습니다.
먼저, createRef라는 리액트 내장 함수를 이용하여 ref의 명을 만들어줍니다.(함수형에선 useRef라는 리액트 훅 이용)
둘째, 접근하고 싶은 돔 요소에 ref속성을 넣어준 후 첫번째에 만들어준 ref명을 넣어줍니다.
셋째, inputRef.current.value 이런식으로 그 ref에 현재 접근한 것의 value값을 가져오는 식을 적어주면 해당 input의 value값을 가져 옵니다.

createRef와 useRef의 차이점

클래스형 컴포넌트는 인스턴스를 생성 후 render 코드 블록 쪽만 리랜더링후 다시 실행 합니다. 하지만 함수형 컴포넌트는 함수 블록 안에 있는 모든 것을 리랜더링시 마다 다시 실행합니다.
때문에, 함수형 컴포넌트에 createRef를 사용 할 시 ref 값이 초기화 되어서 원하는 값을 얻지 못하기 떄문에, 리액트 훅인 useRef를 사용하는 것입니다.
리액트 훅을 사용하면 useState 값을 리랜더링하면 내부적으로 기억하듯이 useRef도 내부적으로 ref값을 기억하여줍니다.

이렇게 ref는 돔요소나 리액트 컴포넌트등에 접근하여 원하는 값을 가져올 수 있게 해주는 고마운 존재입니다.
감사합니다
useRef
Hooks에서만 실행 가능
ref를 만들고 ref의 초기값을 할당함
빈값으로 시작하지 않으므로 빈값 체크할 필요가 없음
createRef
함수 컴포넌트, 클래스 컴포넌트 둘다 사용
ref만 만듬
값을 가져다가 쓸 때 빈값 체크가 필요함
1. 변경 가능한 값
우선 React에서 Ref는 Reference의 줄임말이고 DOM 요소를 참조한다고 해서 붙인 이름 같네요. useRef()는 인자하나를 초기값으로 받고 reference를 return합니다. reference는 current라는 특별한 프로퍼티를 가진 객체입니다.
const reference = useRef(initialValue);

reference.current; // current reference value

refer.current는 레퍼런스의 값에 접근하고 refer.current = newValue는 레퍼런스의 값을 업데이트 합니다.
import { useRef } from 'react';

function MyComponent() {
const reference = useRef(initialValue);

const someHandler = () => {
// Access reference value:
const value = reference.current;

// Update reference value:
reference.current = newValue;

};

// ...
}

여기서 두가지 규칙을 기억해야 합니다.
레퍼런스의 값은 유지 됩니다. 컴포넌트 리렌더링이 된다 하더라도.
레퍼런스의 값의 업데이트는 컴포넌트 리렌더링을 트리거하지 않습니다.
간단한 예제
import { useRef } from 'react';

function LogButtonClicks() {
const countRef = useRef(0);

const handle = () => {
countRef.current++;
console.log(Clicked ${countRef.current} times);
};

console.log('I rendered!');

return Click me;
}

버튼을 클릭하더라도 I rendered 로그는 나타나지 않고(규칙2), Clicked 1 times에서 값은 계속 증가합니다.(규칙1)
Ref와 State의 차이는?
Ref와 state의 차이를 위해 코드를 써 봅니다.
import { useState } from 'react';

function LogButtonClicks() {
const [count, setCount] = useState(0);

const handle = () => {
const updatedCount = count + 1;
console.log(Clicked ${updatedCount} times);
setCount(updatedCount);
};

console.log('I rendered!');

return Click me;
}

state의 update가 있기에 클릭을 할 때마다 I rendered! 로그를 보실 수 있습니다. 해당 코드를 바탕으로 알 수 있는 state와 ref의 두가지 주요한 차이점을 알 수 있습니다.
state를 업데이트하는 것은 컴포넌틑 리렌더링을 트리거하지만 ref는 아닙니다.
상태 업데이트는 비동기적(상태 변수는 렌더링 한 후 업데이트 됨)이지만 참조는 동기적(업데이트된 값은 즉시 사용될 수 있음)입니다.
2. DOM 요소 접근
아래 3단계 과정은 useRef를 이용해 DOM 요소에 접근하는 예제입니다.
useRef를 이용해 elementRef 선언.
elementRef를 div에 할당
컴포넌트가 마운트 되고나서 엘리먼트의 ref속성을 divElement에 할당
import { useRef, useEffect } from 'react';

function AccessingElement() {
const elementRef = useRef();

useEffect(() => {
const divElement = elementRef.current;
}, []);

return (

<div ref={elementRef}>
  I'm an element
</div>

);
}

2-1 사용 사례 : 인풋 포커싱
예를 들어, 컴포넌트가 마운트되고 인풋 필드에대한 포커싱이 필요하다면 DOM 요소들에 대한 접근이 필요합니다.
사용법은 간단합니다.
import { useRef, useEffect } from 'react';

function InputFocus() {
const inputRef = useRef();

useEffect(() => {
inputRef.current.focus();
}, []);

return (

);
}

inputRef를 선언하고, input 태그에 할당한다.
그리고 React는 마운트 후 inputRef.current를 입력 요소로 설정합니다.
그럼 이제 실질적으로 inputRef.current.focus()를 이용해 포커싱을 줄 수 있습니다.
'초기 렌더링 상태에서는 Ref는 null 이다'
import { useRef, useEffect } from 'react';

function InputFocus() {
const inputRef = useRef();

useEffect(() => {
// Logs HTMLInputElement
console.log(inputRef.current);

inputRef.current.focus();

}, []);

// Logs undefined during initial rendering
console.log(inputRef.current);

return ;
}

초기 렌더링 중에는 아직까지 컴포넌트는 생성된 구조가 없다. 그렇기 때문에 초기 렌더링 중에 inputRef.current가 undefined로 나타납니다.
useEffect 단계에서는 DOM이 렌더되고나서 콜백을 호출한다. useEffect에서는 DOM이 보장되기 때문에 올바르게 inputRef.current에 액세스할 수 있다.
3. 참조 제한 업데이트
함수 컴포넌트의 함수 스코프는 output을 계산하거나 hook을 호출해야한다. 그래서 컴포넌트 함수의 즉각적인 범위 내에서 참조 업데이트(상태 업데이트 포함)를 수행해서는 안된다. 참조는 useEffect()의 콜백 내부 또는 핸들러(이벤트, 타이머)내부에서 업데이트 되어야한다.
import { useRef, useEffect } from 'react';

function MyComponent({ prop }) {
const myRef = useRef(0);

useEffect(() => {
myRef.current++; // Good!

setTimeout(() => {
  myRef.current++; // Good!
}, 1000);

}, []);

const handler = () => {
myRef.current++; // Good!
};

myRef.current++; // Bad!

if (prop) {
myRef.current++; // Bad!
}

return My button;
}

4.정리
useRef()는 참조를 생성한다. const reference = useRef(initialValue)는 초기값과 함께 특별한 객체를 생성한다. 참조 객체는 current프로퍼티를 가지고 있다. refer.current를 읽거나 업데이트할 수 있다.
참조 값은 컴포넌트 리렌더링과 별개로 영구적이다.
state의 업데이트와 다르게 참조 업데이트는 컴포넌트 리렌더링을 트리거하지 않는다.
참조는 DOM에 접근할 수 있다.

Element
처럼 할당하고 reference.current를 이용해 접근할 수 있다.
[React] useRef, ref 란 무엇일까?
React에서 제공하는 hook, useRef에 대해서 알아보자. (전체적인 코드는 작성하지 않음, 해당 git 링크에서 clone 받아서 확인 가능)
useRef
useRef는 무엇이고 왜 사용할까? 자세히 들어가면 한도 끝도 없고, 그 정도까지 알 필요도 없다(심화는 천천히). 간단하게만 알아보자. ref는 크게 2가지로 사용이 된다.
1. DOM에 접근한다.
2. 렌더링을 일으키지 않고 값을 변경시킨다.
우선 위 2가지를 알아보자.
1. DOM에 접근한다.
JavaScript에서 DOM에 접근할 때 사용하는 여러가지 방법이 있다. DOM에 접근하는 대표적인 방법이 Document.querySelector(), Document.getElementById()가 있다. 이러한 것들을 대신 ref을 이용하여 DOM에 접근할 수 있다. 간단하게 예시를 들어보자. 아래 코드는 버튼을 클릭하였을 때, input 창에 focus를 하는 코드이다.
return (

<div>
  <input ref={textRef} />
  <button onClick={() => textRef.current.focus()}>
    input에 포커스하기
  </button>
</div>

);
결과를 보면 알 수 있듯이 input 창에 포커싱이 된다.

  1. 렌더링을 일으키지 않고 값을 변경시킨다.
    렌더링을 일으키지 않고 값을 변화시킬 수 있다? 이게 무슨 말일까? 이전 시간에 알아본 state는 값이 변할 때마다 setState를 해주어서 렌더링이 되는 것을 확인하였다. 그러나 ref는 state와 다르게 값이 변하게 되어도 렌더링이 일어나지 않는다. 간단하게 구현하여 확인해보자.
    const Ref = () => {
    const textRef = useRef(null);

    console.log("rendering");

    return (

    <div>
      <input ref={textRef} />
      <button onClick={() => console.log("input 값 : ", textRef.current.value)}>
        값 확인하기
      </button>
    </div>

    );
    };

위 gif를 보면 알 수 있듯이 input에 값을 계속 변화를 주지만 렌더링은 일어나지 않는다. 그럼 저 값을 가지고 오고 싶으면 어떻게 해야할까? 바로 ref.current를 이용하여 DOM에 접근하여 값을 가지고 오는 것이다. 사실 1번 DOM에 접근할 수 있다와 연관이 있는 내용이다.
Controlled(제어) 컴포넌트, Uncontrolled(비제어) 컴포넌트
React에는 제어 컴포넌트와 비제어 컴포넌트가 있다. 간단하게 2개의 차이만 말하자면 제어 컴포넌트는 state를 사용한 것이고, 비제어 컴포넌트는 ref를 사용한 것이다. 2개의 차이점은 분명히 존재한다. React에서는 제어 컴포넌트를 지향하고 있다. 그러나 state를 사용하는 경우 복잡한 form을 구현할 때, 렌더링이 많이 일어나 성능상 느려지는 경우가 발생할 수 있다. 따라서 제어, 비제어 컴포넌트를 상황에 맞게 잘 사용해야 한다. 해당 부분은 아래 걸어둔 React 공식 홈페이지 링크를 읽어보도록 하자.

  • 제어 컴포넌트
  • 비제어 컴포넌트

React 라이브러리는 ref를 왜 만들었을까?
이 글은 해당 질문을 중심으로 ref와 연관된 아래 개념들을 정리하는 글이다.
01. DOM API(querySelector, getElementById)
02. Mutable(변하기 쉬움)과 Immutable(불변성)
03. Declarative(선언형)과 Imperative(명령형)
React에서 Ref
Vanilla Javascript에서는 DOM 객체에 접근하기 위해 querySelector나 getElementById API를 사용해야 한다.
반면, React는 아래와 같은 이유로 DOM API를 이용한 컴포넌트 제어 방식을 권장하지 않는다.
01. React를 이용한 웹 소프트웨어에서 데이터는 State로 조작되기에 DOM API와 혼합해서 데이터 및 조작을 할 경우 디버깅이 어려워지고, 유지보수가 어려운 코드가 된다.
02. map 메소드를 이용해 렌더링 되는 리스트 형태의 Element는 같은 ID를 가지기에 특정 DOM 객체를 querySelector, getElementById로 판별하기 어렵다.
따라서, React는 DOM API를 이용한 컴포넌트 제어 대신 ref라는 기능을 제공한다. ref를 통해 DOM 객체에 대한 직접적인 참조 주소를 반환 받아 HTML DOM 메소드 및 속성을 이용할 수 있다.
[그림 01] HTML DOM 속성에 접근하는 ref의 예시. clientHeight는 HTML DOM의 주요 속성이다.
React에서는 ref기능을 이용하기 위해 React.createRef() 와 useRef() 를 제공한다.
이 둘을 간략하게 구분하면 Class 컴포넌트에서는 createRef()를 사용하고 Functional 컴포넌트에서는 useRef()를 사용한다.
이 둘에 대한 차이는 잠시 미뤄두고 각 기능은 다음과 같이 사용한다.
[그림 02] Class 컴포넌트에서 React.createRef()를 써서 ref를 만드는 예시. current라는 속성으로 값을 조회함
이때, 중요한 것은 createRef()와 useRef()자체는 Mutable Object를 만드는 기능이라는 점이다.
ref는 componentDidMount나 useEffect가 실행되기 전에 할당됩니다.
컴포넌트가 마운트 될 때 할당되며, 언마운트 될 때 Null을 할당합니다.
즉, React Component의 인스턴스나, React DOM의 ref 속성에 해당 ref 참조(this.ref)를 선언하지 않으면 그저 Mutable Object일 뿐이다.
이를 확인하기 위해 createRef의 실제 구현체를 확인해보자.
[그림 03] React.createRef()의 실제 구현체. Object가 Reference 타입의 자료형임을 이용했다.
실제로 createRef()의 구현체를 확인하면 Javascript의 Object가 Reference(참조) 타입의 변수라는 것을 이용한 간단한 코드로 구현된 것을 확인할 수 있다.
즉, createRef()나 useRef()로 생성한 참조주소를 JSX의 ref 속성으로 선언해주어야 해당 컴포넌트 혹은 DOM Element에 대한 참조를 얻을 수 있다.
createRef와 useRef
앞서 Class 컴포넌트에서는 createRef()를 Functional 컴포넌트에서는 useRef()를 쓴다고 언급했다. 이 둘의 차이는 무엇일까?
이 둘의 차이를 이해하기 위해서는 Class 컴포넌트와 Functional 컴포넌트의 리렌더링 차이를 알아야 한다.
글의 진행을 위해 간단하게 설명하면 Class 컴포넌트는 인스턴스를 생성해 render 메소드를 호출하는 방식으로 리렌더링을 한다면, Functional 컴포넌트는 해당 함수를 리렌더링 마다 다시 실행한다.
위와 같은 차이는 Functional 컴포넌트에서 createRef() 메소드를 이용하기 어렵게 한다. 아래 예시 코드를 보자.
[그림 04] Functional 컴포넌트에 createRef를 쓸 경우 Component가 렌더링 될 때마다 ref가 생성된다.
createRef()는 앞서 확인한 것과 같이 그저 Mutable Object를 생성하는 기능이기에 Functional 컴포넌트에서 리렌더링 될 때마다 새로운 Mutable Object를 생성하게 된다.
즉, ref를 이용해 Mutable Object를 만들어도 state가 변경되면 createRef()가 다시 호출되며 새로운 ref를 반환한다.
[그림 05] useRef의 구현체로 별도의 Dispatcher에서 해당 컴포넌트의 Hook을 관리함
이와 같은 문제를 해결하기 위한 방법으로 React에서는 useRef()라는 기능을 제공한다.
useRef는 Hook의 Dispatcher를 통해서 동작하는데 내부적으로 mountRef와 updateRef 를 이용해 동작하는 것을 확인할 수 있다.
[그림 06] useRef의 내부 동작을 담당하는 mountRef와 updateRef의 구현체
mountRef와 updateRef 구현체를 통해 두 가지 사실을 알 수 있다.
첫번째, mountRef는 현재의 Hook에 대한 정보를 보관하는 Object의 memoizedState라는 속성에 ref를 저장하는 방식으로 구현됐다.
두번째, updateRef는 컴포넌트가 업데이트 되어 리 렌더링이 발생할 때 memoizedState를 반환하는 방식으로 구현됐다.
useImperativeHandle와 ForwardRef
React는 기본적으로 Declarative(선언형) 패러다임을 따른다.
즉, 뷰의 동작에 대해 하나 씩 명시하는 것이 아닌 state나 props의 변경에 따라 변하는 뷰를 선언하는 방식으로 개발된다.
하지만, Ref 기능의 경우 기능을 조작하기 위해 Imperative(명령형) 패러다임을 따른다. 아래의 코드를 보자.
[그림 07] Imperative(명령형) 패러다임을 따르는 ref 기능
특정 동작에 대한 메소드를 구현하고 Imperative(명령형) 패러다임으로 개발하는 것을 확인할 수 있다.
ref를 통한 이런 기능은 Class 컴포넌트에서는 기본적으로 동작하지만 내부 메소드를 정의할 수 없는 Functional 컴포넌트에서는 별도의 기능이 필요하다.
React에서는 Functional 컴포넌트에서 ref를 통한 접근을 위해forwardRef()와 useImperativeHandle() 를 제공한다.
[그림 08] useImperativeHandle과 forwardRef를 이용한 명령형 프로그래밍
forwardRef() 는 Functional 컴포넌트에 ref 속성을 이용할 수 있도록 하는 기능으로 해당 함수로 Wrapping 된 컴포넌트는 위와 같이 ref를 매개변수로 받을 수 있게 된다.
React 내부 WorkTag를 확인하면 forwardRef()를 통해 생성된 컴포넌트는 일반 FunctionComponent 태그와 차별을 두는 ForwardRef 태그로 명시된다.
[그림 09] React 내부적으로 동작을 구분하기 위해 사용하는 work tag. ForwardRef를 통한 컴포넌트를 분리함
useImperativeHandle()는 이름 처럼 Imperative(명령형) 동작에 대한 Handler를 제공한다.
즉, ref.current의 속성으로 접근할 수 있는 메소드에 대해 구현하는 부분이다. 이를 통해 부모 컴포넌트에서 자식 컴포넌트의 state를 조작할 수도 있고, 특정 애니메이션을 트리거 할 수도 있다.
결론
이 글을 통해 React에서 제공하는 ref 기능에 대해 다음과 같은 사실을 배울 수 있었다.
01. Ref는 DOM Element 객체나 React Component 인스턴스를 직접 조회할 수 있다.
02. useRef()나 createRef()는 current 속성을 가지는 Mutable Object를 반환한다.
03. Ref기능은 React의 기본 패러다임인 Declarative(선언형)이 아닌 Imperative(명령형) 패러다임의 기능이다.
이런 ref의 특성을 이용하면 특정 DOM의 API를 직접적으로 사용할 수 있고, 렌더링 없이 변경이 필요한 데이터를 관리할 수 있다.
또한, 자식의 state에 부모가 접근할 때나 state로 제어하지 않는 비제어 컴포넌트 를 사용할 때도 ref를 이용할 수 있다.
React를 통해 개발을 진행하다 보면, state와 props 구조의 규칙을 지키면서 개발하기 어려운 요구 사항이 생길 수 있다.
이 글을 통해 그런 요구사항에 대해 "ref 기능을 이용한 색 다른 해결 방법이 있지 않을까?” 고민해 볼 수 있는 관점을 얻은 것 같다.
맺음말
처음 React Native로 앱 개발을 했을 때, 웹을 개발할 때 보다 ref를 많이 써서 당황한 적이 있다.
처음 React를 배울 때 ref는 비중이 높게 다뤄지지 않았기 때문에 자연스레 이 방법이 잘못된 것은 아닌지, 내가 잘 쓰고 있는지에 대한 고민을 많이 했다.
React Native 라이브러리에는 네이티브 기능을 이용하기 위해 ref를 많이 쓴다. 예를 들면 FlatList 의 특정 항목으로 스크롤 이동을 할 때 사용한다.
ref를 통한 조작이 익숙해질 때, 문득 “특정 UI 의 기능 명세가 확실하다면, useImperativeHandler 와 ForwardRef를 통해 UI의 동작 기능을 ref의 메소드로 관리하는 것이 컴포넌트의 모듈화에 더 유용하지 않을까?” 라는 생각이 들었다.
물론 이 방식이 React의 Declarative(선언형) 패러다임에 반하는 것이지만 패러다임에 고정된 생각보다는 사용성의 관점으로 고민이 되는 부분이었다.
혹시나 이 부분에 대한 이유나 혹은 이렇게 개발해 본 경험이 있는 React 개발자가 있다면, 댓글로 남겨주면 많은 사람들에게 도움이 될 것 같다.
useRef
useRef 는 단순 DOM 엘리먼트를 지정하는데만 사용되지 않는다.
useRef 를 통해 클래스의 멤버 변수와 비슷한 역할을 하게 만들 수 있다.
state 와 달리 값의 변화에 의한 리렌더링이 발생하지 않는다.
current 라는 속성을 통해 어느 값이든 보유할 수 있는 일종의 컨테이너 역할을 할 수 있다.
함수형 컴포넌트는 인스턴스로 생성되지 않는다. 즉, 컴포넌트의 고유한 값을 저장할 방법이 없어 useRef를 통해 일종의 멤버변수를 구현하는 것.
다음의 코드는 ref 를 사용하여 state의 이전 값 을 보관하는 prevMathScore 라는 변수를 만든 예제이다.
import React, { useState, useEffect, useRef } from "react";

function Score() {
const [mathScore, setMathScore] = useState(40);
const prevMathScore = useRef(40);

useEffect(() => {
prevMathScore.current = mathScore;
}, [mathScore]);

const result = prevMathScore.current < mathScore ? "올랐네요" : "개판이네요";

return (
<>
<button onClick={() => setMathScore(mathScore + 20)}>시험보기
{성적이 ${result}! }
</>
);
}

요약해보자면,
1.
state는 컴포넌트의 생명 주기와 밀접한 연관이 있는 요소이므로 렌더링과 관련 없는 값을 저장하기에는 적합치 않다.
2.
ref는
setTimeout, setInterval이 반환하는 ID 값
state의 이전 값
이 외 렌더링과 무관한 가변값
위와 같이 렌더링과 관련이 없는 값을 저장하기에 적합하다.


출처:https://nukw0n-dev.tistory.com/14[찐이의 개발 연결구과]

https://kyounghwan01.github.io/blog/React/useRef-createRef/#%E1%84%92%E1%85%A1%E1%86%B7%E1%84%89%E1%85%AE%E1%84%92%E1%85%A7%E1%86%BC-%E1%84%8F%E1%85%A5%E1%86%B7%E1%84%91%E1%85%A9%E1%84%82%E1%85%A5%E1%86%AB%E1%84%90%E1%85%B3

profile
풀스택 웹개발자👩‍💻✨️

0개의 댓글