[번역] 리액트 19 업그레이드 가이드

eunbinn·2024년 12월 23일
37

FrontEnd 번역

목록 보기
39/39
post-thumbnail

원문: https://react.dev/blog/2024/04/25/react-19-upgrade-guide

리액트 19에 추가된 개선 사항들은 일부 호환성이 깨지는 변경사항이 동반되지만, 최대한 원활한 업그레이드가 되도록 노력했으며 대부분의 앱에는 영향을 미치지 않을 것으로 예상됩니다.


📝 참고사항

리액트 18.3이 배포되었습니다.
리액트 19로의 업그레이드를 더 쉽게 하기 위해, 18.2와 동일하지만 지원 중단 예정인 API에 대한 경고와 리액트 19를 사용하기 위해 필요한 변경사항들이 추가된 react@18.3 버전을 배포했습니다.

리액트 19로 업그레이드하기 전에 먼저 리액트 18.3으로 업그레이드하여 잠재적인 문제를 파악하시기를 권장합니다.

18.3의 변경사항 목록은 릴리스 노트를 참조하세요.


이 글에서는 리액트 19로 업그레이드하는 방법을 안내해드립니다.

리액트 19를 테스트하는 데 도움을 주고 싶으시다면, 이 업그레이드 가이드의 단계들을 따라 진행하시고 발견하신 문제점들을 보고해주세요. 리액트 19에 추가된 새로운 기능들의 목록은 리액트 19 릴리즈 포스트를 참조하세요.

설치하기


📝 참고사항

새로운 JSX 변환은 이제 필수입니다

2020년에 번들 크기를 개선하고 리액트를 import하지 않고도 JSX를 사용할 수 있도록 새로운 JSX 변환(Transform)을 도입했습니다. 리액트 19의 ref를 prop으로 사용하는 것, JSX 속도 개선과 같은 추가적인 개선사항들은 새로운 변환을 필요로 합니다.

새로운 변환이 활성화되어 있지 않다면, 다음과 같은 경고가 표시될 것입니다.

앱(또는 의존성 중 하나)이 구버전 JSX 변환을 사용하고 있습니다. 더 빠른 성능을 위해 최신 JSX 변환으로 업데이트하세요: https://react.dev/link/new-jsx-transform

대부분의 환경에서 이미 변환이 활성화되어 있기 때문에 대부분의 앱은 영향을 받지 않을 것으로 예상됩니다. 수동으로 업그레이드하는 방법에 대한 안내는 공지 글을 참조해 주세요.


최신 버전의 리액트와 리액트 DOM을 설치하기 위해 다음 작업을 진행해주세요.

npm install --save-exact react@^19.0.0 react-dom@^19.0.0

Yarn을 사용하고 있다면 다음을 진행해주세요.

yarn add --exact react@^19.0.0 react-dom@^19.0.0

타입스크립트를 사용한다면 타입도 업데이트 해야합니다.

npm install --save-exact @types/react@^19.0.0 @types/react-dom@^19.0.0

Yarn을 사용한다면 아래와 같이 진행해주세요.

yarn add --exact @types/react@^19.0.0 @types/react-dom@^19.0.0

일반적으로 필요한 변환을 지원하기 위한 codemod도 포함하고 있습니다. 아래의 타입스크립트 변경사항을 참조하세요.

코드 자동 변환 (Codemods)

업그레이드를 돕기 위해, codemod.com 팀과 협력하여 리액트 19의 새로운 API와 패턴으로 코드를 자동으로 업데이트할 수 있는 codemod를 배포했습니다.

모든 codemod는 react-codemod 저장소에서 사용할 수 있으며, Codemod 팀이 codemod 유지보수를 돕기 위해 참여했습니다. 이 codemod를 실행하기 위해서는 react-codemod 대신 codemod 명령어를 사용하시는 것을 권장합니다. 더 빠르게 실행되고, 더 복잡한 코드 마이그레이션을 처리하며, 타입스크립트에 대한 더 나은 지원을 제공합니다.


📝 참고사항

모든 리액트 19 codemod 실행하기

리액트 19 codemod 레시피를 사용하면 이 가이드에 나열된 모든 codemod를 실행할 수 있습니다.

npx codemod@latest react/19/migration-recipe

이는 react-codemod에서 다음의 codemod를 실행할 것입니다:

이는 타입스크립트 변경사항을 포함하지 않습니다. 아래의 타입스크립트 변경사항을 참조하세요.


codemod가 포함되어 있는 변경사항들은 아래에 명령어가 포함되어 있습니다.

사용 가능한 모든 codemod의 목록은 react-codemod 저장소를 참조하세요.

호환성이 깨지는 변경사항

렌더링 중 발생한 에러는 다시 던지지 않습니다

이전 버전의 리액트에서는 렌더링 중에 발생한 에러를 잡아서 다시 발생시켰습니다. 개발 환경에서는 console.error로도 기록하여 중복된 에러 로그가 발생했습니다.

리액트 19에서는 오류를 다시 발생시키지 않음으로써 중복을 줄이도록 에러 처리 방식을 개선했습니다.

  • 잡히지 않은 에러: Error Boundary에 의해 잡히지 않은 오류는 window.reportError에 보고됩니다.
  • 잡힌 에러: Error Boundary에 의해 잡힌 오류는 console.error에 보고됩니다.

이 변경사항은 대부분의 앱에 영향을 미치지 않을 것이지만, 만약 프로덕션 환경의 에러 리포팅이 에러가 다시 발생하는 것에 의존하고 있다면 에러 처리를 업데이트해야 할 수 있습니다. 이를 지원하기 위해 createRoothydrateRoot에 사용자 정의 에러 처리를 위한 새로운 메소드를 추가했습니다.

const root = createRoot(container, {
  onUncaughtError: (error, errorInfo) => {
    // ... 에러 리포트 로그
  },
  onCaughtError: (error, errorInfo) => {
    // ... 에러 리포트 로그
  },
});

더 자세한 정보는 createRoothydrateRoot의 문서를 참조하세요.

더 이상 사용되지 않는 리액트 API들이 제거되었습니다

제거된 API: 함수 컴포넌트의 propTypesdefaultProps

PropTypes2017년 4월(v15.5.0)에 지원 중단되었습니다.

리액트 19에서는 리액트 패키지에서 propType 검사를 제거했으며, 만약 사용했다면 조용히 무시될 것입니다. propTypes를 사용하고 계신다면, 타입스크립트나 다른 타입 검사 솔루션으로 마이그레이션하시는 것을 권장합니다.

또한 함수 컴포넌트에서 defaultProps 대신 ES6 기본 매개변수를 사용하도록 변경했습니다. 클래스 컴포넌트는 ES6 대안이 없기 때문에 계속해서 defaultProps를 지원할 것입니다.

// 이전
import PropTypes from "prop-types";

function Heading({ text }) {
  return <h1>{text}</h1>;
}
Heading.propTypes = {
  text: PropTypes.string,
};
Heading.defaultProps = {
  text: "Hello, world!",
};
// 이후
interface Props {
  text?: string;
}
function Heading({ text = "Hello, world!" }: Props) {
  return <h1>{text}</h1>;
}

📝 참고사항

propTypes를 타입스크립트로 변경하는 Codemod

npx codemod@latest react/prop-types-typescript

제거된 API: contextTypesgetChildContext를 사용하는 레거시 Context

레거시 Context는 2018년 10월(v16.6.0)에 지원 중단되었습니다.

레거시 Context는 contextTypesgetChildContext API를 사용하는 클래스 컴포넌트에서만 사용 가능했으며, 놓치기 쉬운 미묘한 버그들 때문에 contextType으로 대체되었습니다. 리액트 19에서는 리액트를 조금 더 작고 빠르게 만들기 위해 레거시 Context를 제거했습니다.

아직 클래스 컴포넌트에서 레거시 Context를 사용하고 계신다면, 새로운 contextType API로 마이그레이션해야 합니다.

// 이전
import PropTypes from "prop-types";

class Parent extends React.Component {
  static childContextTypes = {
    foo: PropTypes.string.isRequired,
  };

  getChildContext() {
    return { foo: "bar" };
  }

  render() {
    return <Child />;
  }
}

class Child extends React.Component {
  static contextTypes = {
    foo: PropTypes.string.isRequired,
  };

  render() {
    return <div>{this.context.foo}</div>;
  }
}
// 이후
const FooContext = React.createContext();

class Parent extends React.Component {
  render() {
    return (
      <FooContext value="bar">
        <Child />
      </FooContext>
    );
  }
}

class Child extends React.Component {
  static contextType = FooContext;

  render() {
    return <div>{this.context}</div>;
  }
}

제거된 API: 문자열 refs

문자열 ref는 2018년 3월(v16.3.0)에 지원 중단되었습니다.

클래스 컴포넌트는 여러 이슈들 때문에 ref 콜백으로 대체되기 전까지 문자열 ref를 지원했습니다. 리액트 19에서는 리액트를 더 단순하고 이해하기 쉽게 만들기 위해 문자열 ref를 제거했습니다.

아직 클래스 컴포넌트에서 문자열 ref를 사용하고 계신다면, ref 콜백으로 마이그레이션해야 합니다.

// 이전
class MyComponent extends React.Component {
  componentDidMount() {
    this.refs.input.focus();
  }

  render() {
    return <input ref="input" />;
  }
}
// 이후
class MyComponent extends React.Component {
  componentDidMount() {
    this.input.focus();
  }

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

📝 참고사항

문자열 ref를 ref callback으로 변경하는 Codemod

npx codemod@latest react/19/replace-string-ref

제거된 API: 모듈 패턴 팩토리

모듈 패턴 팩토리는 2019년 8월(v16.9.0)에 지원 중단되었습니다.

이 패턴을 지원하는 것은 리액트를 필요 이상으로 크고 느리게 만들었지만 사용률은 아주 낮았습니다. 리액트 19에서는 모듈 패턴 팩토리에 대한 지원을 제거했으며, 일반 함수로 마이그레이션해야 합니다.

// 이전
function FactoryComponent() {
  return {
    render() {
      return <div />;
    },
  };
}
// 이후
function FactoryComponent() {
  return <div />;
}

제거된 API: React.createFactory

createFactory2020년 2월(v16.13.0)에 지원 중단되었습니다.

createFactory 사용은 JSX가 널리 지원되기 전에 일반적이었지만, 오늘날에는 거의 사용되지 않으며 JSX로 대체할 수 있습니다. 리액트 19에서는 createFactory를 제거했으며 사용하고 있다면 JSX로 마이그레이션해야 합니다.

// 이전
import { createFactory } from "react";

const button = createFactory("button");
// 이후
const button = <button />;

제거된 API: react-test-renderer/shallow

리액트 18에서는 react-shallow-renderer를 다시 내보내도록 react-test-renderer/shallow를 업데이트했습니다. 리액트 19에서는 react-test-renderer/shallow를 제거하며 패키지를 직접 설치하는 것을 지향합니다.

npm install react-shallow-renderer --save-dev
- import ShallowRenderer from 'react-test-renderer/shallow';
+ import ShallowRenderer from 'react-shallow-renderer';

📝 참고사항

shallow rendering을 재고해 주세요.

Shallow rendering은 리액트 내부 동작에 의존하기 때문에 향후 업그레이드를 방해할 수 있습니다. 테스트를 @testing-library/react 또는 @testing-library/react-native로 마이그레이션하시는 것을 권장합니다.


더 이상 사용되지 않는 리액트 DOM API들이 제거되었습니다

제거된 API: react-dom/test-utils

actreact-dom/test-utils에서 제거하고 react 패키지로 옮겼습니다.

ReactDOMTestUtils.act는 더 이상 사용되지 않고 React.act를 사용하는 것을 권장합니다. react-dom/test-utils 대신 react에서 act를 import 하세요. 자세한 내용은 https://react.dev/warnings/react-dom-test-utils 을 참조하세요.

위 경고를 해결하기 위해서는 actreact에서 import해야 합니다.

- import {act} from 'react-dom/test-utils'
+ import {act} from 'react';

다른 모든 test-utils 함수들은 제거되었습니다. 이러한 유틸리티들은 일반적으로 잘 사용되지 않았고, 컴포넌트와 리액트의 낮은 수준의 구현 세부사항에 너무 쉽게 의존하게 만들었습니다. 리액트 19에서는 이러한 함수들을 호출할 때 에러가 발생할 것이며, 이후 버전에서는 이러한 내보내기(exports)들이 완전히 제거될 예정입니다.

대안으로 해당 경고 페이지를 참고해주세요.


📝 참고사항

ReactDOMTestUtils.actReact.act로 변환하는 Codemod

npx codemod@latest react/19/replace-act-import

제거된 API: ReactDOM.render

ReactDOM.render2022년 3월(v18.0.0)에 지원 중단되었습니다. 리액트 19에서는 ReactDOM.render가 제거되므로 ReactDOM.createRoot로 마이그레이션해야 합니다.

// 이전
import { render } from "react-dom";
render(<App />, document.getElementById("root"));

// 이후
import { createRoot } from "react-dom/client";
const root = createRoot(document.getElementById("root"));
root.render(<App />);

📝 참고사항

ReactDOM.renderReactDOMClient.createRoot로 변환하는 Codemod

npx codemod@latest react/19/replace-reactdom-render

제거된 API: ReactDOM.hydrate

ReactDOM.hydrate2022년 3월(v18.0.0)에 지원 중단되었습니다. 리액트 19에서는 ReactDOM.hydrate가 제거되므로 ReactDOM.hydrateRoot로 마이그레이션해야 합니다.

// 이전
import { hydrate } from "react-dom";
hydrate(<App />, document.getElementById("root"));

// 이후
import { hydrateRoot } from "react-dom/client";
hydrateRoot(document.getElementById("root"), <App />);

📝 참고사항

ReactDOM.hydrateReactDOMClient.hydrateRoot로 변환하는 Codemod

npx codemod@latest react/19/replace-reactdom-render

제거된 API: unmountComponentAtNode

ReactDOM.unmountComponentAtNode2022년 3월(v18.0.0)에 지원 중단되었습니다. 리액트 19에서는 root.unmount()로 마이그레이션해야 합니다.

// 이전
unmountComponentAtNode(document.getElementById("root"));

// 이후
root.unmount();

root.unmount()에 대해 더 많은 정보를 알고 싶으시다면 createRoothydrateRoot를 참고하세요.


📝 참고사항

unmountComponentAtNoderoot.unmount로 변환하는 Codemod

npx codemod@latest react/19/replace-reactdom-render

제거된 API: ReactDOM.findDOMNode

ReactDOM.findDOMNode2018년 10월(v16.6.0)에 지원 중단되었습니다.

findDOMNode는 실행이 느리고, 리팩토링에 취약하며, 첫 번째 자식만 반환하고, 추상화 레벨을 깨뜨리는 오래된 임시방편이였기 때문에 제거하기로 했습니다(자세히 보기). ReactDOM.findDOMNodeDOM refs로 대체할 수 있습니다.

// 이전
import { findDOMNode } from "react-dom";

function AutoselectingInput() {
  useEffect(() => {
    const input = findDOMNode(this);
    input.select();
  }, []);

  return <input defaultValue="Hello" />;
}
// 이후
function AutoselectingInput() {
  const ref = useRef(null);
  useEffect(() => {
    ref.current.select();
  }, []);

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

새롭게 지원 중단하는 기능

지원 중단: element.ref

리액트 19는 ref를 prop으로서 제공하기 때문에 element.ref를 지원 중단하고 element.props.ref를 사용할 것을 권장합니다.

element.ref에 접근하면 아래와 같은 경고가 발생합니다.

element.ref에 접근하는 것은 더 이상 지원하지 않습니다. ref는 이제 일반적인 prop으로 사용할 수 있습니다. 따라서 추후 릴리즈에서 JSX 엘리먼트 타입에서 제거될 예정입니다.

지원 중단: react-test-renderer

저희는 react-test-renderer를 더 이상 사용하지 않기로 했습니다. 이는 사용자들이 사용하는 환경과 일치하지 않는 자체 렌더러 환경을 구현하고, 구현 세부사항 테스트를 조장하며, 리액트 내부에 의존하기 때문입니다.

이 테스트 렌더러는 React Testing Library와 같은 더 유용한 테스트 전략들이 있기 전에 만들어졌으며, 이제는 이러한 현대적인 테스트 라이브러리를 사용할 것을 권장합니다.

리액트 19에서는 react-test-renderer에서 지원 중단 경고가 표시되고, 동시성 렌더링을 하도록 전환되었습니다. 현대적이고 더욱 잘 지원되는 테스트 경험을 위해 여러분의 테스트를 @testing-library/react 또는 @testing-library/react-native로 마이그레이션할 것을 권장합니다.

주목할 만한 변경사항

StrictMode 변경

리액트 19에서는 Strict Mode에 여러 개선사항과 수정사항이 포함되었습니다.

개발 환경에서 Strict Mode로 인한 이중 렌더링이 발생할 때, useMemouseCallback은 두 번째 렌더링에서 첫 번째 렌더링의 메모이제이션된 결과를 재사용하게 됩니다. 컴포넌트들이 이미 Strict Mode와 호환된다면 동작에 있어 특별한 차이를 느끼지 못할 것입니다.

다른 Strict Mode의 기능들과 마찬가지로, 이러한 특징들은 개발 단계에서 컴포넌트의 잠재적인 버그를 미리 발견하고 프로덕션 배포 전에 수정할 수 있도록 설계되었습니다. 예를 들어, 개발 환경에서 Strict Mode는 초기 마운트 시 ref 콜백 함수를 두 번 호출하는데, 이는 마운트된 컴포넌트가 Suspense fallback으로 대체될 때 발생할 수 있는 상황을 시뮬레이션하기 위한 것입니다.

Suspense 개선사항

리액트 19에서는 컴포넌트가 suspense 상태가 되면, 리액트는 형제 트리 전체의 렌더링이 완료되기를 기다리지 않고 즉시 가장 가까운 Suspense 경계의 fallback을 표시합니다. fallback이 적용된 후에는, 리액트는 트리의 나머지 부분에서 지연 로딩되는 요청들을 미리 준비하기 위해 일시 중단된 형제 컴포넌트들의 렌더링을 다시 스케줄링합니다.

image
이전 버전에서는 컴포넌트가 suspense 상태가 되면, 일시 중단된 형제 컴포넌트들이 먼저 렌더링된 후에 fallback UI가 적용되었습니다.

image
리액트 19에서는 컴포넌트가 suspense 상태가 되면, 먼저 fallback UI가 적용되고 그 후에 일시 중단된 형제 컴포넌트들이 렌더링됩니다.

이는 Suspense fallback UI를 더 빠르게 표시하면서도, 백그라운드에서는 실제 컨텐츠를 위한 데이터나 리소스를 계속해서 준비할 수 있도록 합니다.

UMD 빌드 제공 중단

과거에는 리액트를 빌드 과정 없이 간편하게 로드하기 위해 UMD(Universal Module Definition) 방식이 널리 사용되었습니다. 하지만 이제는 HTML 문서에서 모듈을 스크립트로 로드하는 더 현대적인 방법들이 등장했습니다. 이에 따라 리액트 팀은 테스트와 배포 프로세스를 단순화하기 위해 리액트 19부터는 UMD 빌드 제공을 중단하기로 결정했습니다.

script 태그로 리액트 19를 로드하려면 esm.sh와 같은 ESM(ECMAScript Module) 기반의 CDN을 사용하는 것을 권장합니다.

<script type="module">
  import React from "https://esm.sh/react@19/?dev"
  import ReactDOMClient from "https://esm.sh/react-dom@19/client?dev"
  ...
</script>

리액트 내부에 의존하는 라이브러리들이 업그레이드를 방해할 수 있습니다

이번 릴리스에는 리액트 내부의 변경사항이 포함되어 있습니다. 이는 우리가 '절대 사용하지 말라'고 경고했던 SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED와 같은 내부 기능을 무시하고 사용한 라이브러리들에 영향을 미칠 수 있습니다. 이러한 변경은 리액트 19의 개선사항을 적용하기 위해 필요한 것이며, 가이드라인을 준수한 라이브러리들에는 영향을 주지 않습니다.

우리의 버전 관리 정책에 따르면, 이러한 업데이트들은 주요 변경사항(breaking changes)으로 분류되지 않으며, 업그레이드 방법에 대한 문서도 제공하지 않을 것입니다. 내부 기능에 의존하는 모든 코드를 제거할 것을 권장합니다.

내부 기능 사용이 미치는 영향을 더 명확히 전달하기 위해, SECRET_INTERNALS 접미사를 다음과 같이 변경했습니다.

_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE

앞으로는 사용을 더욱 강력히 제한하고 사용자들의 업그레이드가 방해받지 않도록 하기 위해, 리액트의 내부 기능 접근을 더 적극적으로 차단할 예정입니다.

타입스크립트 변경사항

지원 중단된 타입스크립트 타입 제거

리액트 19에서 제거된 API들을 기반으로 타입스크립트 타입들을 정리했습니다. 일부 제거된 타입들은 더 관련성 있는 패키지로 이동되었고, 일부는 리액트의 동작을 설명하는 데 더 이상 필요하지 않게 되었습니다.


참고
대부분의 타입 관련 주요 변경사항을 쉽게 마이그레이션하기 위해 types-react-codemod를 배포했습니다.

npx types-react-codemod@latest preset-19 ./path-to-app

만약 element.props에 대한 불안정한 접근이 많다면, 다음과 같은 추가 codemod를 실행해보세요.

npx types-react-codemod@latest react-element-default-any-props ./path-to-your-react-ts-files

지원되는 대체 목록은 types-react-codemod를 확인하세요. Codemod가 누락된 부분이 있다면 리액트 19 누락된 codemod 목록에서 확인할 수 있습니다.

ref 정리 필수

이 변경사항은 react-19 codemod 프리셋의 no-implicit-ref-callback-return에 포함되어 있습니다.

ref 정리 함수의 도입으로 인해, ref 콜백에서 다른 것을 반환하는 것은 이제 타입스크립트에서 거부됩니다. 일반적으로 암묵적 반환을 사용하지 않도록 수정하면 됩니다.

- <div ref={current => (instance = current)} />
+ <div ref={current => {instance = current}} />

원래 코드는 HTMLDivElement의 인스턴스를 반환했고 타입스크립트는 이것이 정리 함수인지 아닌지 알 수 없었습니다.

useRef는 인자가 필요합니다

이 변경사항은 react-19 codemod 프리셋의 refobject-defaults에 포함되어 있습니다.

타입스크립트와 리액트가 작동하는 방식에 대한 오랜 불만 중 하나가 useRef였습니다. 이제 useRef가 인자를 필요로 하도록 타입을 변경했습니다. 이는 타입 시그니처를 크게 단순화합니다. 이제 createContext와 더 비슷하게 동작할 것입니다.

// @ts-expect-error: 인자가 1개 필요하지만 없음
useRef();
// 통과
useRef(undefined);
// @ts-expect-error: 인자가 1개 필요하지만 없음
createContext();
// 통과
createContext(undefined);

이는 이제 모든 ref가 변경 가능함을 의미하기도 합니다. null로 초기화했기 때문에 ref를 변경할 수 없는 문제가 더 이상 발생하지 않습니다.

const ref = useRef<number>(null);
// 'current'는 읽기 전용 속성이므로 할당할 수 없음
ref.current = 1;

MutableRef는 이제 useRef가 항상 반환할 단일 RefObject 타입을 위해 더 이상 사용되지 않습니다.

interface RefObject<T> {
    current: T
}
declare function useRef<T>: RefObject<T>

useRef는 여전히 useRef<T>(null)에 대해 자동으로 RefObject<T | null>을 반환하는 오버로드를 가지고 있습니다. useRef의 필수 인자로 인한 마이그레이션을 쉽게 하기 위해, 자동으로 RefObject<T | undefined>를 반환하는 useRef(undefined)에 대한 오버로드가 추가되었습니다.

이 변경사항에 대한 이전 논의는 [RFC] Make all refs mutable을 참조하세요.

ReactElement 타입스크립트 타입의 변경사항

이 변경사항은 react-element-default-any-props codemod에 포함되어 있습니다.

리액트 엘리먼트의 props는 이제 ReactElement로 타입이 지정된 경우 기본값이 any 대신 unknown으로 설정됩니다. ReactElement에 타입 인자를 전달했다면 영향을 주지 않습니다.

type Example2 = ReactElement<{ id: string }>["props"];

//    ^? { id: string }

만약 타입 인자 전달 없이 기본값을 사용했다면, 이제 unknown을 처리해야 합니다.

type Example = ReactElement["props"];

//    ^? 이전에는 'any'였으나, 이제는 'unknown'

이는 엘리먼트 props에 대한 타입 체크를 우회하거나 무시하며 접근하는 레거시 코드가 많은 경우에만 필요합니다. 엘리먼트 검사(Element introspection)는 일종의 우회로서 존재하며, 명시적으로 any를 사용함으로써 props 접근이 안전하지 않다는 것을 명확히 표현해야 합니다.

타입스크립트의 JSX 네임스페이스

이 변경사항은 react-19 codemod 프리셋의 scoped-jsx에 포함되어 있습니다.

오랫동안 요청되어 온 변경사항으로, 전역 JSX 네임스페이스를 React.JSX로 대체했습니다. 이를 통해 JSX를 활용하는 다른 UI 라이브러리들 간의 충돌을 방지하고 전역 타입의 오염을 막을 수 있습니다.

이제 JSX 네임스페이스의 모듈 확장을 declare module "…"로 감싸야 합니다.

// global.d.ts

+ declare module "react" {
    namespace JSX {
      interface IntrinsicElements {
       "my-element": {
          myElementProps: string;
        };
      }
    }
+ }

정확한 모듈 지정자는 tsconfig.jsoncompilerOptions에서 지정한 JSX 런타임에 따라 다릅니다.

  • "jsx": "react-jsx"의 경우 react/jsx-runtime
  • "jsx": "react-jsxdev"의 경우 react/jsx-dev-runtime
  • "jsx": "react""jsx": "preserve"의 경우 react

향상된 useReducer 타입

@mfp22 덕분에 useReducer는 이제 더 나은 타입 추론을 제공합니다.

하지만 이로 인해 useReducer가 전체 리듀서 타입을 타입 매개변수로 받지 않고, 컨텍스트 타입 추론에 의존하거나 상태와 액션 타입을 모두 필요로 하는 breaking change가 발생했습니다.

가장 좋은 방법은 useReducer에 타입 인자를 전달하지 않는 것입니다.

- useReducer<React.Reducer<State, Action>>(reducer)
+ useReducer(reducer);

상태와 액션의 타입을 명시적으로 지정할 수 있는 엣지 케이스의 경우, Action을 튜플로 전달할 수 있습니다.

-  useReducer<React.Reducer<State, Action>>(reducer)
+  useReducer<State, [Action]>(reducer);

reducer를 인라인으로 정의하는 경우, 함수 매개변수에 타입을 추가하는 것을 권장합니다.

- useReducer<React.Reducer<State, Action>>((state, action) => state)
+ useReducer((state: State, action: Action) => state)

reducer를 useReducer 호출 밖으로 이동하는 경우에도 동일하게 적용됩니다.

const reducer = (state: State, action: Action) => state;

변경 이력

기타 호환성이 깨지는 변경사항

  • react-dom: srchref에서 자바스크립트 URL에 대한 에러 처리 #26507
  • react-dom: onRecoverableError에서 errorInfo.digest 제거 #28222
  • react-dom: unstable_flushControlled 제거 #26397
  • react-dom: unstable_createEventHandle 제거 #28271
  • react-dom: unstable_renderSubtreeIntoContainer 제거 #28271
  • react-dom: unstable_runWithPriority 제거 #28271
  • react-is: react-is에서 더 이상 사용되지 않는 메서드 제거 #28224

기타 주목할 만한 변경사항

  • react: 동기, 기본 및 연속 레인 일괄 처리 #25700
  • react: 일시 중단된 컴포넌트의 형제 요소 사전 렌더링 중단 #26380
  • react: 렌더링 단계 업데이트로 인한 무한 업데이트 루프 감지 #26625
  • react-dom: popstate에서의 전환이 이제 동기적으로 처리됨 #26025
  • react-dom: SSR 중 layout effect 경고 제거 #26395
  • react-dom: src/href에 빈 문자열 설정 시 경고 표시 및 설정 중단(앵커 태그 제외) #28124

전체 변경사항은 Changelog를 참조하세요.

0개의 댓글