TypeScript에 React18 적용하기

Seungmin Shin·2022년 4월 6일
10

React

목록 보기
1/1

React 18이 업데이트 되었다.

리액트 18이 나온것은 알고있었다. 하지만 그건 찬찬히 공부하기로 하고 지금 하고 있던
프로젝트를 켰는데 콘솔창에 이런 에러문구가 나오더라.

react-dom.development.js:86 Warning: ReactDOM.render is 
no longer supported in React 18. Use createRoot instead.
Until you switch to the new API, your app will behave as 
if it's running React 17

번역하자면

react-dom.development.js:86 경고: ReactDOM.render는 React 18 에서
더 이상 지원되지 않습니다. 대신 createRoot를 사용하십시오. 새 API로 전환할
때까지 앱은 React 17을 실행하는 것처럼 작동합니다.

라는 내용이다. 가만있어보자, ReactDOM.render 라면....

index.ts 파일에서 App.ts 를 html 로 렌더해주는 녀석 아닌가?
그래서 확인해봤다.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(      // <- 이부분
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

여기다. 그렇다면 저 문구의 뜻대로라면.. 이제 저 ReactDOM.render 는 리액트 18에선
더이상 지원되지 않으니 createRoot 를 사용하라는 것이군... 오케이 확인

그렇다면 저 문구를 계속 보기 싫으니 createRoot 를 사용해주겠다.

package.json 확인

일단 현재 프로젝트의 package.json 을 확인해보자.

"dependencies": {
    "@testing-library/jest-dom": "^5.16.3",
    "@testing-library/react": "^12.1.4",
    "@testing-library/user-event": "^13.5.0",
    "@types/jest": "^27.4.1",
    "@types/node": "^16.11.26",
    "@types/react": "^17.0.43",
    "@types/react-dom": "^17.0.14",
    "react": "^18.1.0-next-af730436c-20220405",
    "react-dom": "^18.1.0-next-af730436c-20220405",
    "react-scripts": "5.0.0",
    "typescript": "^4.6.3",
    "web-vitals": "^2.1.4"
  },

현재 내 react 버전은 18버전이 되어있다. 만약 17버전을 가지고 있다면 업데이트를 해주자

yarn add react@next react-dom@next

index.ts 확인

그렇게 18버전이 되었다면 index.ts 로 넘어가서 아까의 코드를 수정해주자.

Before

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

After

import React from 'react';
import ReactDOM from "react-dom/client";
import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

잘 되는가? 아마 오류가 날것이다. 만약 이 프로젝트가 자바스크립트였다면 정상적으로
작동했겠지만, 우리는 타입스크립트를 사용하기때문에 오류가 발생했다.

아마

Property 'createRoot' does not exist on type 'typeof
import("/code/my-app/node_modules/@types/react-dom/index")'. TS2339

이런 오류일것이다. 타입유형에 createRoot 라는 속성이 없다는것이다.
현재 프로젝트에는 해당 API가 정의되어있지 않기 때문이다.

그렇다면 이제 그 유형을 업그레이드 해보자.

yarn add @types/react @types/react-dom

자, 이제 된거같지만 여전히 오류가 발생한다. 이쯤에서 살짝 올라오지만 잘 참고 끝까지
해보자.

선언한 타입을 실제프로젝트에 로드해야되는데 하나의 과정이 남아있다.

tsconfig.json 의 compilerOption 에 react/next 를 추가하는것이다.

"types": ["react/next", "react-dom/next"]

이런식으로 추가해주자.

그럼 드디어 된건가???? 놉. 여전히 오류가 난다.하지만 좀 다른 오류가 나왔다.

Argument of type 'HTMLElement | null' is not assignable to
parameter of type 'Element | DocumentFragment'.
Type 'null' is not assignable to type 'Element | DocumentFragment'.
형식 인수 ''Element | DocumentFragment' 형식의 매개 변수에
HTMElement | null'을(를) 할당할 수 없습니다.
'null' 유형은 'Element | DocumentFragment' 유형에 할당할 수 없습니다.

이 오류는 타입스크립트에서 null 을 반환할 수 없다는 뜻인데, 이 부분을 손봐주면 된다.

import React from 'react';
import ReactDOM from "react-dom/client";
import './index.css';
import App from './App';

const rootElement = document.getElementById('root');
if (!rootElement) throw new Error('Failed to find the root element');
const root = ReactDOM.createRoot(rootElement);

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

rootElement 가 null 일 경우의 조건문을 만들어 에러처리시키면 정상적으로 동작한다.

이렇게 타입스크립트에 리액트18을 얹는 과정이 끝났다. 계속 적응해봅시다.

참고사이트
https://blog.logrocket.com/how-to-use-typescript-with-react-18-alpha/

profile
Frontend Developer

1개의 댓글

comment-user-thumbnail
2024년 1월 7일

감사합니다

답글 달기