-
기존 프로젝트 react v17 -> v18 업그레이드 로그FrontEnd 2022. 4. 24. 22:00
React v18이 나왔다는 기쁜 소식에 기존 프로젝트의 react와 react-dom 버전을 최신으로 올리려고 봤더니
Conflicting peer dependency 에러가 뜬다.
@reduxjs/toolkit에서 react@"^16.14.0 || ^17.0.0"만 지원하도록 설정해두었기 때문이다.
최신 버전으로 올리면 React v18을 지원하는지 살펴보니 최근에 업데이트가 되었다.
그럼 toolkit 버전을 올리면 되겠지?
npm install @reduxjs/toolkit@latest
그러려면 먼저 react-redux 버전을 올려줘야 한다.
npm install react-redux@latest
그랬더니 redux-toolkit 버전이 낮아서 안 된다는 에러가 뜬다.
닭이 먼저냐 달걀이 먼저냐를 해결하려면 둘을 동시에 업데이트해줘야 한다.
npm install react-redux@latest @reduxjs/toolkit@latest
리덕스가 해결되었다.
잊지말고 @testing-library/react 버전도 올려줘야 한다.
올리지 않고 테스트를 돌리면 이런 워닝이 뜬다.
npm install @testing-library/react@latest
업데이트를 마치고 프로젝트를 확인해보는데 라우터가 작동하지 않는다. 살펴보니 이런 이슈가 있다.
https://github.com/facebook/react/issues/21674
react-router-dom@v5에서 동작하지 않는다고 한다. 이것도 버전을 올려준다.
npm install react-router-dom@latest
react-router-dom은 API 변화가 있다.
업데이트하고 공식문서의 변경사항을 참고해서 바뀐 부분을 수정한다.
- <Switch /> -> <Routes />
- <Redirect>s inside <Switch> -> <Route path="/sth" element={<Navigate to="path"} />} />
- useHistory -> useNavigate와 관련 api 변경사항
- 그리고 regex 지원 범위 축소 대응
기존에 지원되던 ? 옵션이 빠져서 약간 당황했지만,
/:parent/:child? 를 /:parent와 /:parent/:child로 각각 쪼개서 넣어주면 정상적으로 작동하는 걸 확인할 수 있다.
useParams를 쓰면 /:parent일 때 child는 undefined로 들어오기 때문에 문제 없다.
내 경우 child가 없는 경우를 default로 처리하려했던 거라서, 이제는 /parent에서 따로 redirect를 해주는 게 더 나을 것 같다.
하지만 이건 리팩토링에서 추가로 다루기로 하고 지금은 넘어간다.
react-router-dom까지 버전 업데이트를 하고 나니 드디어 React v18에서 제대로 작동한다.
아직 React18의 기능을 직접 써본 건 없지만 일단 한 걸음 내딛었다는데 의의를 두기로 한다.
덧붙임
React 18을 지원하지 않는 dependency 처리 이야기
프로젝트 기존 dependency 중에 react-dnd-multi-backend가 있었다.
작업 도중 드래그 앤 드롭 부분에서 react-dnd의 도움을 받았는데, react-dnd는 마우스와 터치 동시 지원이 안 되는 아쉬움이 있다.
물론 react-dnd-touch-backend를 이용하고 enableMouseEvents 옵션을 주면 사용가능하지만, 문서에서 언급하고 있듯이 버그가 좀 있다.
이 문제를 해결하기 위해 도입한 것이 react-dnd-multi-backend.
처음 작업 당시엔 터치 디바이스를 지원할 생각이 없었어서 깊게 생각하지 않았다가, 프로젝트 마무리 시점에 모바일도 지원하면 좋을 것 같고, 마침 적합한 라이브러리가 있어서 깊게 고민하지 않고 도입했었던 기억이 난다.
그런데 React 버전을 올리려니까 Conflicting peer dependency 이슈가 있다.
- react-dnd-multi-backend에서 react18을 지원해줄 때까지 버전 업데이트를 미루거나
- react-dnd-multi-backend를 걷어내고 대체재를 물색하거나
결정을 해야했다.
물론 react-dnd-multi-backend에 직접 PR을 올리는 게 가장 이상적인 해결책이겠지만, 쉽지 않을 것 같고 그렇게까지 리소스를 투입하기는 어려워서 다른 방법을 찾기로 했다.
검색을 좀 해보니 마땅한 라이브러리 대체재는 보이지 않았다.
그럼 여기서 스톱?
생각해보니 JS단에서 touch device를 감지하는 방법이 분명 있을 것 같다.
그럼 redux에 backend를 세팅하는 시점에 디바이스 종류를 파악해서 걸맞은 라이브러리를 넣어주면 되지 않을까?
라는 생각에 도달, 검색해보니 무려 11년 전에 올라온 답변이 있다.
whats-the-best-way-to-detect-a-touch-screen-device-using-javascript
isTouchDevice 헬퍼를 이용해서 backend를 조건부로 넣는 것에 성공.
이제 react-dnd-multi-backend 의존성이 사라졌으니 해당 라이브러리를 들어내도 된다.
import { HTML5Backend } from "react-dnd-html5-backend"; import { TouchBackend } from "react-dnd-touch-backend"; import App from "./App"; import store from "./app/store"; import isTouchDevice from "./helpers/device"; const backend = isTouchDevice() ? TouchBackend : HTML5Backend; const container = document.getElementById("root"); const root = createRoot(container); root.render( <React.StrictMode> <Provider store={store}> <DndProvider backend={backend}> <Router> <App /> </Router> </DndProvider> </Provider> </React.StrictMode>, );
그러고보니 처음부터 이렇게 했어도 됐을 것 같다.
물론 임시방편이고, 마우스와 터치를 둘다 지원하는 디바이스가 있다면 한쪽만 먹힐 테니 최종적으로는 멀티를 처리하는 방향으로 가야하겠지만.
대신 이 방법은 dynamic import를 할 수 있으니 속도가 조금 향상될 수 있을 것 같기도 하고.
이런 부분을 고려하면, 라이브러리를 선택할 때 peer dependency 여부/볼륨도 중요하다.
모든 프로젝트가 제때 업데이트되는 건 아니니까, 특정 라이브러리에 의존하게 되면 전체 업데이트 사이클이 종속돼버린다.
no dependency 라이브러리들이 인기를 끌고 있는 이유를 직접 체감할 수 있었던 좋은 경험이었다.
'FrontEnd' 카테고리의 다른 글
python not found after macOS update to Monterey (0) 2022.04.24