Upgrading to React 18 in SonarQube: Insights and Challenges
The SonarQube platform, developed using React, recently underwent an upgrade from version 17 to 18. This transition, involving TypeScript and the use of Jest alongside React Testing Library (RTL) for testing, presented several challenges. Our aim here is to share the three main hurdles we encountered during this upgrade and the valuable lessons we learned along the way. These challenges included changes in TypeScript types, the necessity to update React Testing Library, and the breaking changes introduced with React 18.
Delving into the specifics, let's examine what these issues entailed and our strategies for addressing them. This article is a collaborative effort by SonarQube's front-end team, comprising David Cho-Lerat, Ambroise Christea, and Philippe Perrin.
A significant point noted in the React 18 upgrade guide is the requirement to update both @types/react and @types/react-dom. A key change is the explicit listing of the 'children' prop in props definitions. Thankfully, Sebastian Silbermann from the React core team provides a set of codemods for an easier transition. These codemods, executable via npx, automate the update process:
npx types-react-codemod preset-18 ./src
They offer a range of transforms, including the explicit listing of the 'children' prop, facilitating a smoother upgrade. However, caution is advised as the codemod may result in nested PropsWithChildren types, which, while not harmful, should be corrected upon discovery.
The updated types also bring stricter requirements in certain areas. For instance, overriding the 'children' type in an interface, which was feasible in React 17, is no longer possible in React 18 without first omitting the 'children' declaration. Additionally, the types for parameters in a useCallback function now require explicit declaration.
Upgrading @types/react to version 18 may introduce several issues, especially in testing. Post-update, many tests that previously passed began failing due to timing issues and calls to act(). React Testing Library's use of setTimeout for user event simulation clashed with Jest's fake timers, causing tests to hang. However, RTL's introduction of an advanceTimers option in version 14.1.0, which allows the use of jest.advanceTimersByTime, resolved these issues.
Moreover, excessive calls to act(), previously a workaround for act(...) warnings, now resulted in test failures. Removing these redundant calls resolved the problem, as suggested by Kent C. Dodds in his comprehensive post on addressing act(...) warnings in RTL.
React 18 introduces substantial changes at the application's root, notably replacing ReactDOM.render with createRoot. This change not only alters how React manages the application root but also how it renders the application. Two features, automatic batching and the new concurrent renderer, are enabled by this update. Concurrent rendering, which can be opted into using the useTransition hook, allows React to prioritize certain tasks. Automatic batching, on the other hand, consolidates state changes into a single update for improved performance but may lead to unexpected behaviors.
Our experience revealed that this new batching can affect code execution within the same scope, leading to test failures. To address this, it's crucial to ensure code execution post-state update, either using the callback form of setState or the new ReactDOM.flushSync() method.
Asynchronous rendering posed challenges in our tests, as the content was not immediately present on initial renders. Switching from RTL's synchronous getBy queries to the asynchronous await findBy query resolved this issue by allowing the DOM time to update.
The upgrade to React 18 on the SonarQube UI was successful, highlighting the importance of a comprehensive test suite in identifying necessary updates and ensuring application readiness. These insights from our upgrade journey should prove helpful for those planning a move from React 17 to 18, preparing them for potential pitfalls.
original article: Upgrading to React 18 in SonarQube: Insights and Challenges by SonarQube