본문으로 건너뛰기
개발 머꼬
개발 노트React
hohyeon.dev36

React 19로 올렸더니 propTypes와 findDOMNode가 사라져서 깨진 부분

  • #Engineering Note
  • #React
  • #Upgrade

문제 발생

React 18에서 19로 올린 뒤 두 가지가 동시에 일어났습니다. 하나는 앱이 시작조차 못 하는 오류였고, 다른 하나는 아무 경고 없이 기본값이 사라져 화면에 undefined가 찍히는 문제였습니다.

// 1) 즉시 터진다
ReactDOM.render(<App />, document.getElementById("root"));
// TypeError: ReactDOM.render is not a function

// 2) 조용히 달라진다
function Heading({ text }) { return <h1>{text}</h1>; }
Heading.defaultProps = { text: "Hello, world!" };  // 더 이상 적용되지 않음

원인 분석

React 19는 여러 버전에 걸쳐 deprecated였던 API를 실제로 제거했습니다. 업그레이드가 까다로운 이유는 제거 방식이 두 종류이기 때문입니다.

즉시 터지는 것 — 함수 자체가 없어져 첫 실행에서 바로 드러납니다.

제거된 것대체
ReactDOM.rendercreateRoot(container).render(<App />)
ReactDOM.hydratehydrateRoot(container, <App />)
ReactDOM.unmountComponentAtNoderoot.unmount()
ReactDOM.findDOMNodeuseRef로 DOM 참조
react-dom/test-utilsactimport { act } from "react"

조용히 달라지는 것 — 호출은 성공하는데 효과만 없어집니다. 테스트가 없으면 배포 후에 발견됩니다.

  • 함수 컴포넌트의 propTypesdefaultProps — 검증도 기본값 주입도 일어나지 않습니다.
  • 문자열 ref(ref="input") — 콜백 ref로 바꿔야 합니다.
  • 레거시 컨텍스트(contextTypes, getChildContext) — createContext로 옮겨야 합니다.

findDOMNode는 특히 조심할 부분입니다. 직접 쓰지 않아도 오래된 서드파티 컴포넌트가 내부에서 쓰고 있는 경우가 많아, 우리 코드를 다 고쳐도 라이브러리에서 터집니다.

해결 방안

  1. 기본값은 매개변수 기본값으로 옮깁니다. 타입 검증은 TypeScript가 대신합니다.
// 이전
function Heading({ text }) { return <h1>{text}</h1>; }
Heading.defaultProps = { text: "Hello, world!" };

// 이후
function Heading({ text = "Hello, world!" }) { return <h1>{text}</h1>; }
  1. findDOMNode는 ref로 대체합니다. 감싸는 DOM 노드를 추측하는 대신 원하는 노드를 직접 가리킵니다.
function AutoselectingInput() {
  const ref = useRef(null);
  useEffect(() => { ref.current.select(); }, []);
  return <input ref={ref} defaultValue="Hello" />;
}
  1. 먼저 18의 마지막 마이너로 올려 경고를 모두 없앱니다. 19에서 제거된 것들은 18에서 이미 경고를 내고 있었으므로, 경고가 0이 된 상태에서 19로 올리면 남는 문제가 훨씬 적습니다.
  2. 의존성이 19를 지원하는지 확인합니다. findDOMNode나 문자열 ref는 우리 코드보다 오래된 라이브러리에 남아 있을 확률이 높습니다.
  3. 공식 codemod를 활용합니다. 업그레이드 가이드가 제공하는 codemod로 기계적인 치환은 자동화할 수 있습니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.