Skip to content

Commit

Permalink
add:2024-01-28-MigrateReact17to18.md
Browse files Browse the repository at this point in the history
  • Loading branch information
momoci99 committed Jan 28, 2024
1 parent 3b8acf9 commit 6fdf1ca
Showing 1 changed file with 205 additions and 0 deletions.
205 changes: 205 additions & 0 deletions _posts/2024-01-28-MigrateReact17to18.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
---
layout: single
title: "React 17 to 18 migration"
tag:
- React
---

현재 회사에서 react 17 → react 18 버전으로 마이그레이션을 준비하고 있어 관련 내용을 정리합니다

다루는것

- 클라이언트 사이드에서 마이그레이션시 검토해야하는 부분

다루지 않는것

- 서버사이드 렌더링
- react native

## roots api 변경

- root render 모듈이 react-dom → react-dom/client로 변경
- react 18에서 제공하는 creeatRoot에서 렌더링 성능이 개선되었음.
- creactRoot는 batch 렌더링을 지원.

```jsx
// Before
import { render } from "react-dom";
const container = document.getElementById("app");
render(<App tab="home" />, container);

// After
import { createRoot } from "react-dom/client";
const container = document.getElementById("app");
const root = createRoot(container); // createRoot(container!) if you use TypeScript
root.render(<App tab="home" />);
```

## unmountComponentAtNode → root.unmount 로 변경

- dom에서 react 컴포넌트를 제거하는 api

```jsx
// Before
unmountComponentAtNode(container);

// After
root.unmount();
```

## render함수에 대한 callback 제거

- suspense 동작에 이슈가 있어 변경됨.

```jsx
// Before
const container = document.getElementById("app");
render(<App tab="home" />, container, () => {
console.log("rendered");
});

// After
function AppWithCallbackAfterRender() {
useEffect(() => {
console.log("rendered");
});

return <App tab="home" />;
}

const container = document.getElementById("app");
const root = createRoot(container);
root.render(<AppWithCallbackAfterRender />);
```

## Strict Mode 동작 변경

이전보다 더 강력하게 동작이 변경됨

**react 17**

변경 발생시

- 변경된 컴포넌트에 대한 마운트만 다시 수행

```jsx
* React mounts the component.
* Layout effects are created.
* Effect effects are created.
```

**react 18**

변경 발생시

- 컴포넌트 mounte
- 컴포넌트 unmount 시뮬레이트
- 이전 상태와 함께 컴포넌트 마운팅

```jsx
* React mounts the component.
* Layout effects are created.
* Effect effects are created.
* React simulates unmounting the component.
* Layout effects are destroyed.
* Effects are destroyed.
* React simulates mounting the component with the previous state.
* Layout effect setup code runs
* Effect setup code runs
```

## 타입스크립트 정의 업데이트

- @types/reac, @types/react-dom 라이브러리에 대한 최신 버전 업데이트가 필요함.
- (그런데 병원 웹은 사용하지 않고 있고, 파트너에는 이미 최신 메이저 버전(18)을 사용중임)
- props 정의시 children에 대한 props를 명시적으로 지정해주어야함.

```jsx
interface MyButtonProps {
color: string;
children?: React.ReactNode;
}
```

## 자동 batching

**react 17**

- react 이벤트 핸들러 내부에서만 일괄 처리 수행
- Promise, setTimeout, 기본 이벤트 핸들러 or 기타 이벤트 내부에서의 상태 업데이트는 react에서 일괄처리하지 않음

```jsx
// Before React 18 only React events were batched

function handleClick() {
setCount((c) => c + 1);
setFlag((f) => !f);
// setState는 2번 정의되어있으나 한번만 re-render 수행(일괄처리)
}

setTimeout(() => {
setCount((c) => c + 1);
setFlag((f) => !f);
// re-redenr를 두번 수행(일괄처리 안됨)
}, 1000);
```

**react 18**

- createRoot 내부에서 발생하는 모든 상태 업데이트는 일괄처리됨.

```jsx
// react 18 및 그 이후버전 부터는 timeouts, promises, native event를 비롯한
// 모든 이벤트들은 일괄처리됩니다.

function handleClick() {
setCount((c) => c + 1);
setFlag((f) => !f);
// setState는 2번 정의되어있으나 한번만 re-render 수행(일괄처리)
}

setTimeout(() => {
setCount((c) => c + 1);
setFlag((f) => !f);
// setState는 2번 정의되어있으나 한번만 re-render 수행(일괄처리)
}, 1000);
```

## 새로운 api

**useSyncExternalStore**

- 외부 스토어를 연동하기 위함 hook. 그러나 대부분의 상태 관리 라이브러리에서는 이미 사용중

**useInsertionEffect**

- css-in-js에서 렌더링 도중에 스타일이 업데이트 되는 경우 리엑트에서 렌더링을 멈추고 브라우저가 레이아웃을 다시 계산할 수 있도록 함.
- styled-component를 위한 전용 hook

**IE 를 더이상 지원하지 않음**

- react 17까지만 IE를 지원.

Deprecations

- `react-dom``ReactDOM.render` has been deprecated. Using it will warn and run your app in React 17 mode.
- `react-dom``ReactDOM.hydrate` has been deprecated. Using it will warn and run your app in React 17 mode.
- `react-dom``ReactDOM.unmountComponentAtNode` has been deprecated.
- `react-dom``ReactDOM.renderSubtreeIntoContainer` has been deprecated.
- `react-dom/server``ReactDOMServer.renderToNodeStream` has been deprecated.

다른 Breaking Changes

- 컴포넌트에서 undefined를 반환해도 warn이 노출되지 않고 렌더링 될 수 있도록 변경
- react-testing-library에서 e2e테스트를 실행할때 act warning이 더이상 발생하지 않음. 필요할때만 발생시키도록 환경변수 제공
- unmounted된 컴포넌트에서 setState호출시 warning 미출력으로 변경.
- React 17까지는 unmounted된 컴포넌트에서 setState 호출시 메모리 누수에 대해 경고를 하였으나 불필요한것으로 판단하여 제거됨
- Strict모드에서 console.log가 두번씩 호출되는부분을 React 17에서는 한번씩으로 억제하는 기능이 있었으나 혼란을 야기한다는 의견을 바탕으로 해당기능을 제거함 (console.log가 두번씩 노출 in strict모드)
- mounted 해제시 더 많은 내부 필드를 제거하여 잠재적인 메모리 누수 감소.

참고 자료

- https://react.dev/blog/2022/03/08/react-18-upgrade-guide
- [https://velog.io/@code-bebop/react-17에서-18으로-마이그레이션](https://velog.io/@code-bebop/react-17%EC%97%90%EC%84%9C-18%EC%9C%BC%EB%A1%9C-%EB%A7%88%EC%9D%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EC%85%98)
- https://react.dev/blog/2022/03/08/react-18-upgrade-guide#updates-to-strict-mode
- https://github.com/reactwg/react-18/discussions/5

0 comments on commit 6fdf1ca

Please sign in to comment.