Skip to content

Latest commit

 

History

History
435 lines (318 loc) · 12.5 KB

File metadata and controls

435 lines (318 loc) · 12.5 KB
title findDOMNode

이 API는 향후 React의 주요 버전에서 제거될 예정입니다. 대안들을 살펴보세요.

findDOMNode는 React의 클래스 컴포넌트에서 브라우저의 DOM 노드를 찾는 방법입니다.

const domNode = findDOMNode(componentInstance)

레퍼런스 {/reference/}

findDOMNode(componentInstance) {/finddomnode/}

findDOMNode를 호출하여 주어진 클래스 컴포넌트에서 브라우저의 DOM 노드를 찾습니다.

import { findDOMNode } from 'react-dom';

const domNode = findDOMNode(componentInstance);

아래 예시를 참고하세요.

매개변수 {/parameters/}

  • componentInstance: 컴포넌트 하위 클래스의 인스턴스입니다. 예를 들어 클래스 컴포넌트의 경우 this가 포함되어 있습니다.

반환값 {/returns/}

findDOMNode는 주어진 componentInstance에서 가장 처음 등장하는 브라우저 DOM 노드를 반환합니다. 컴포넌트가 null이나 false를 렌더링할 경우 findDOMNodenull을 반환합니다. 컴포넌트가 문자열을 렌더링하면 findDOMNode는 그 값을 포함한 텍스트 DOM 노드를 반환합니다.

주의 사항 {/caveats/}

  • 컴포넌트가 배열이나 다수의 자식을 가진 Fragment를 반환할 수 있습니다. 이런 경우 findDOMNode는 해당하는 DOM 노드 중 비어있지 않은 첫 번째 자식을 반환합니다.

  • findDOMNode는 컴포넌트가 마운트 되었을 때(즉, 컴포넌트가 DOM에 배치되었을 때)만 동작합니다. 컴포넌트가 아직 마운트 되지 않은 상태에서 호출할 경우 (예시로 컴포넌트가 생성되기 전인 render() 내에서 findDOMNode()를 호출하는 경우) 예외가 발생합니다.

  • findDOMNode는 호출할 당시의 결과만 반환합니다. 이후에 자식 컴포넌트가 다른 노드를 렌더링하더라도, 그 변화에 대해 알 수 없습니다.

  • findDOMNode는 클래스 컴포넌트에서만 사용할 수 있습니다. 함수 컴포넌트에서는 사용할 수 없습니다.


사용법 {/usage/}

클래스 컴포넌트의 root DOM 노드를 찾기 {/finding-the-root-dom-node-of-a-class-component/}

클래스 컴포넌트 인스턴스에서 findDOMNode를 호출하여 (주로 this) 이를 렌더링한 DOM 노드를 찾습니다.

class AutoselectingInput extends Component {
  componentDidMount() {
    const input = findDOMNode(this);
    input.select()
  }

  render() {
    return <input defaultValue="Hello" />
  }
}

여기서 input 변수는 <input> DOM 요소를 값으로 갖게 됩니다. 이제 이것을 통해 작업이 가능해집니다. 예를 들어 "Show example"을 클릭하여 입력창을 마운트하고, input.select()로 입력창의 모든 문자를 선택하도록 합니다.

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
import { Component } from 'react';
import { findDOMNode } from 'react-dom';

class AutoselectingInput extends Component {
  componentDidMount() {
    const input = findDOMNode(this);
    input.select()
  }

  render() {
    return <input defaultValue="Hello" />
  }
}

export default AutoselectingInput;

대안 {/alternatives/}

ref를 통해 컴포넌트의 DOM 노드 읽기 {/reading-components-own-dom-node-from-a-ref/}

findDOMNode를 사용하는 코드는 JSX 노드와 이에 해당하는 코드 사이의 연결이 명시적이지 않아 취약합니다. 예시로 <input /><div>로 감싸보세요.

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
import { Component } from 'react';
import { findDOMNode } from 'react-dom';

class AutoselectingInput extends Component {
  componentDidMount() {
    const input = findDOMNode(this);
    input.select()
  }
  render() {
    return <input defaultValue="Hello" />
  }
}

export default AutoselectingInput;

이제 코드가 깨질 텐데, 코드는 findDOMNode(this)<input> DOM 노드를 찾을 것으로 기대하고 있었지만 실제로 찾은 것은 <div> DOM 노드이기 때문입니다. 이러한 문제를 방지하기 위해 특정 DOM 노드를 관리할 때는 createRef를 사용하세요.

이 예시에선 findDOMNode는 더 이상 사용하지 않습니다. 대신 inputRef = createRef(null)를 클래스의 인스턴스 필드에 정의하였습니다. 여기서 this.inputRef.current를 통해 DOM 노드를 읽을 수 있습니다. 이것을 JSX에 붙이려면, <input ref={this.inputRef} />를 렌더링합니다. 이 작업은 DOM 노드를 사용하는 코드와 JSX를 연결합니다.

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
import { createRef, Component } from 'react';

class AutoselectingInput extends Component {
  inputRef = createRef(null);

  componentDidMount() {
    const input = this.inputRef.current;
    input.select()
  }

  render() {
    return (
      <input ref={this.inputRef} defaultValue="Hello" />
    );
  }
}

export default AutoselectingInput;

클래스 컴포넌트를 사용하지 않는 최신 React에서는, useRef를 대신 호출하여 동일한 기능을 구현합니다.

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
import { useRef, useEffect } from 'react';

export default function AutoselectingInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    const input = inputRef.current;
    input.select();
  }, []);

  return <input ref={inputRef} defaultValue="Hello" />
}

refs를 사용한 DOM 조작에 대해 더 알아보세요.


forwarded ref를 사용하여 자식 컴포넌트의 DOM 노드를 읽기 {/reading-a-child-components-dom-node-from-a-forwarded-ref/}

이 예시에서는 findDOMNode(this)가 다른 컴포넌트에 속한 DOM 노드를 찾습니다. AutoselectingInput 컴포넌트는 브라우저의 <input>을 렌더링하는 MyInput 컴포넌트를 렌더링합니다.

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
import { Component } from 'react';
import { findDOMNode } from 'react-dom';
import MyInput from './MyInput.js';

class AutoselectingInput extends Component {
  componentDidMount() {
    const input = findDOMNode(this);
    input.select()
  }
  render() {
    return <MyInput />;
  }
}

export default AutoselectingInput;
export default function MyInput() {
  return <input defaultValue="Hello" />;
}

AutoselectingInput 컴포넌트의 내부에서 findDOMNode(this)를 호출하면, <input>에 대한 JSX가 MyInput 컴포넌트 내부에 숨겨져 있더라도 문제없이 <input> DOM 노드를 찾아낼 수 있습니다. 이러한 동작이 위 예시에서는 편리해 보일 수 있겠지만, 결국은 취약한 코드로 가는 밑거름이 됩니다. 만약 나중에 코드를 수정하며 MyInput<div>로 감싼다고 생각해 보세요. <input>을 찾을 것으로 기대하던 AutoselectingInput의 코드를 깨뜨리게 됩니다.

위 예시의 findDOMNode를 대체하려면, 두 컴포넌트가 협력해야 합니다.

  1. AutoSelectingInput에서는 ref를 선언해야 하고, 이전의 예시처럼 <MyInput>으로 전달합니다.
  2. MyInputforwardRef로 선언해야 하며, 해당 ref를 가져와 <input> 노드로 전달합니다.

아래 방식으로 사용하면 더 이상 findDOMNode가 필요하지 않습니다.

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
import { createRef, Component } from 'react';
import MyInput from './MyInput.js';

class AutoselectingInput extends Component {
  inputRef = createRef(null);

  componentDidMount() {
    const input = this.inputRef.current;
    input.select()
  }

  render() {
    return (
      <MyInput ref={this.inputRef} />
    );
  }
}

export default AutoselectingInput;
import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
  return <input ref={ref} defaultValue="Hello" />;
});

export default MyInput;

클래스 컴포넌트 대신 함수 컴포넌트에서 사용할 때는 이런 코드로 동작합니다.

import { useState } from 'react';
import AutoselectingInput from './AutoselectingInput.js';

export default function App() {
  const [show, setShow] = useState(false);
  return (
    <>
      <button onClick={() => setShow(true)}>
        Show example
      </button>
      <hr />
      {show && <AutoselectingInput />}
    </>
  );
}
import { useRef, useEffect } from 'react';
import MyInput from './MyInput.js';

export default function AutoselectingInput() {
  const inputRef = useRef(null);

  useEffect(() => {
    const input = inputRef.current;
    input.select();
  }, []);

  return <MyInput ref={inputRef} defaultValue="Hello" />
}
import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
  return <input ref={ref} defaultValue="Hello" />;
});

export default MyInput;

감싸주는 <div> 요소 추가하기 {/adding-a-wrapper-div-element/}

컴포넌트는 종종 자식의 위치와 크기를 알아야 할 때가 있습니다. 때문에 findDOMNode(this)를 사용하여 자식들을 찾고, 측정을 위해 getBoundingClientRect와 같은 DOM 메서드를 사용하게 됩니다.

이러한 사용 사례에 직접적으로 대응되는 방법이 없기 때문에 findDOMNode는 더 이상 사용되지 않음에도 React에서 완전히 사라지지는 않았습니다. 그동안 이를 해결하기 위해 콘텐츠 주위를 <div> 노드로 감싸주고, 그 노드의 ref를 가져왔습니다. 하지만, 콘텐츠를 감싸는 요소를 추가하는 방법은 스타일을 손상할 수 있습니다.

<div ref={someRef}>
  {children}
</div>

이는 특정 항목에 초점을 맞추고 스크롤을 하는 경우에도 적용됩니다.