ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 기존 프로젝트 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을 지원하는지 살펴보니 최근에 업데이트가 되었다.

     

    Release v1.8.1 · reduxjs/redux-toolkit

    This release updates RTK's peer dependencies to accept React 18 as a valid version. This should fix installation errors caused by NPM's "install all the peer deps and error if they don't match" be...

    github.com

    그럼 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 18: react-router@v5 is breaking in the Strict Mode (strict effects) · Issue #21674 · facebook/react

    remix-run/react-router#7870 I do not have permission to post https://github.com/reactwg/react-18/discussions. Please open and pin a new issue in that repo to list all widely-used library that does ...

    github.com

    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

    댓글

Designed by Tistory.