React

Ref와 DOM

삐옹 2022. 5. 23. 14:00

Javascript와 React는 DOM에 접근하는 방식이 조금 다릅니다.

차이를 먼저 알아보겠습니다.

vanilaJS

javascript에서 DOM 엘리먼트를 수정하려는 경우엔, 해당 DOM을 지정하기 위해 *선택자를 사용합니다. 

/* <div id="my-id">안녕하세요</div> */ 

// 예시 
const myElement = document.querySelector('#my-id'); 
myElement.style.color = 'yellow';

하지만 vanillaJS와는 달리 react에서는 특정 DOM을 직접적으로 수정해야 하는경우 ref를 사용합니다.

 

*선택자

document.getElementsById()

document.querySelector()

document.querySelectorAll()

...

 

React

ref를 사용하는 경우는 다음과 같습니다.

1. 특정 element에 포커스, 속성값을 관리할 때(특히 input).
2. 특정 element에 애니메이션을 직접적으로 실행시킬 때(transition, animation 이런거).
3. 서드 파티 DOM 라이브러리를 React와 같이 사용할 때(react랑 쓸 수 있는 서드 파티 DOM 라이브러리라는게 있나보다).

 

ref prop

컴포넌트의 생성자 안에서 inputRef 객체를 생성해 변수에 담습니다

const InpuRef = useRef(null); // 초깃값 null

이렇게 inputRef 변수를 input 태그의 ref property로 넘기게 되면,

<input ref={inputRef} />

이 inputRef 객체의 current속성을 통해서 input 엘리먼트에 접근할 수 있고,

console.log(iunputRef // {current : input}

current 속성에 접근하여 DOM API를 이용해 input 엘리먼트를 제어할 수 있습니다.

 

useRef

함수형 컴포넌트에서 DOM에 접근하려 할 때는 useRef라는 API를 사용합니다.

// 초기값이 initialValue인 ref prop 생성
const refContainer = useRef(initialValue);

 예시

function CustomTextInput(props) {
  // 1. textInpuRef 객체 생성
  const textInpuRef = useRef(null);

  function handleClick() {
  	
  	// 3. inputRef 객체의 current 속성에는 <input> 엘리먼트의 레퍼런스가 저장됩니다
    console.log(textInpuRef) //{current: input} 
    
    // 4.textInpuRef.current로 <input> 엘리먼트 제어합니다
    textInpuRef.current.focus(); 
  }

	// 2. DOM노드와 생성자에서 정의된 'textInpuRef' 객체 연결
  return (
    <div>
      <input
        type="text"
        ref={textInpuRef} /> 
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );
}

클래스형 컴포넌트

클래스형 컴포넌트에서 DOm에 접근하려 할 때는 createRef라는 API를 사용합니다.

예시

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    // 1. textInput DOM 엘리먼트를 저장하기 위한 ref를 생성합니다.
    this.textInput = React.createRef();
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
    // 3. DOM API를 사용하여 명시적으로 text 타입의 input 엘리먼트를 포커스합니다.
    // 주의: 우리는 지금 DOM 노드를 얻기 위해 "current" 프로퍼티에 접근하고 있습니다.
    this.textInput.current.focus();
  }

  render() {
    // 2. React에게 우리가 text 타입의 input 엘리먼트를
    // 우리가 생성자에서 생성한 `textInput` ref와 연결하고 싶다고 이야기합니다.
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

 


마치며

 

react에서 ref prop을 이용하여 어떻게 HTML 엘리먼트에 직접 접근할 수 있는지에 대하여 알아보았습니다.

 

ref prop에서 한가지 주의할 점은 HTML 엘리먼트를 직접 제어하는 것은 JQuery 시절에 주로 쓰이던 명령형(imperative) 방식의 웹 프로그래밍이라는 것 입니다. 프로그래밍 패러다임 중 하나인 선언형(declarative) 프로그래밍 패러다임을 기반으로 하는 react를 포함한 vue, Angular에서는 반드시 필요한 경우가 아니라면 이러한 접근 방식은 지양하는 것이 좋습니다.

 

참조

https://ko.reactjs.org/docs/hooks-reference.html#useref

 

Hooks API Reference – React

A JavaScript library for building user interfaces

ko.reactjs.org

https://www.daleseo.com/react-refs/

 

[React] ref로 HTML 엘리먼트에 접근/제어하기

Engineering Blog by Dale Seo

www.daleseo.com

 

명령형 vs 선언형 프로그래밍

https://boxfoxs.tistory.com/430

 

명령형 프로그래밍 VS 선언형 프로그래밍

명령형 프로그래밍과 선언형 프로그래밍에 대한 비교를 어디선가 한 번쯤은 접해봤을 거라 생각합니다. 그리고 그 둘이 실제로 무엇을 의미하는지 검색을 해보셨다면 아마 아래와 같은 정의를

boxfoxs.tistory.com