Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React v18: WiP #523

Open
wants to merge 197 commits into
base: main
Choose a base branch
from
Open

React v18: WiP #523

wants to merge 197 commits into from

Conversation

Gnito
Copy link
Contributor

@Gnito Gnito commented Jan 8, 2025

This updates Sharetribe Web Template to work with React v18.3.1

Notes for ppl taking update from this repo:

react-dom has been split
react-dom/server is a separated from the rest of the package. Template loads this separately (but we kept the file structure the same).

sharetribe-scripts
The dependency had a somewhat embarrasing bug with Loadable Components setup causing hydration issue with v18. The earlier React versions were able to resolve the issue silently, but v18 is more strict to enforce that the server-side rendered (SSR) HTML matches with the HTML created on the first rendering pass on the browser / client-side rendering (CSR).

The fix was small (one-liner), but it caused UI issue on SearchPage (map layout was broken). Therefore, the new release for the sharetribe-scripts is going to be a major one (instead of a patch release).

Other hydration issues
There were some components that used typeof window === 'undefined' type of checks directly on rendering function. Those will cause hydration issues with React v18 (as SSR returns true and CSR returns false), if the check causes different HTML structure.

Similarly, some components used matchMedia to change HTML on for mobile and desktop layouts. With React v18, you need to make the first pass on CSR to match with the SSR. One way to do that is to track when the component is mounted:

const MyComponent = props => {
  const [mounted, setMounted] = useState(false);
  useEffect(() => {
    setMounted(true);
  }, []);
  
  const isMobileLayout =
    mounted && window?.matchMedia ? window.matchMedia(`(max-width: 767px)`)?.matches : true;

 return isMobileLayout ? <div>Hello</div> : <main>world</main>;
};

With this kind of code, the first CSR rendering does not pick 'desktop' layout. There will be a second rendering pass after the mounted flag is turned to true.

Dependency libraries
Several dependency libraries have been updated to support React v18.

Spreading key prop from list items throws a warning
Component's key can't be spread from collection of props anymore.

-        const { schemaType, ...fieldProps } = customFieldProps;
+        const { schemaType, key, ...fieldProps } = customFieldProps;
         return schemaType === SCHEMA_TYPE_MULTI_ENUM ? (
-          <SectionMultiEnumMaybe {...fieldProps} />
+          <SectionMultiEnumMaybe key={key} {...fieldProps} />

defaultProps and propTypes
React v18.3.1 has deprecated defaultProps in favor of JavaScripts (ES6) native default parameters for spread. This PR changes all the places, where defaultProps has been used. In addition, propTypes will also be removed on next React version (v19). Therefore, we have removed propTypes too and added the same information as JSDoc comment for the exported components.

If you want to postpone defaultProps removal, you could choose v18.2 instead of v18.3.1. The latter gives the warning about deprecation.

Most of the changes in this PR is about propTypes & JSDoc comments.

Tests
There was changes to the Testing Library setup (we started to use act as rendering became more asynchronous with the updated libraries). Note: act is imported differently between React v18.2 and v18.3.1. If you choose to use v18.2, you need to import act from the React Testing Library instead of importing it directly from React.

What about server components?
We didn't start to use server components at this point. It would affect only few public routes (landing page, search, listing and profile pages mainly) and we already have SSR in place for the public pages. Furthermore, relevant page schema for bots that don’t render JavaScript, won’t be available if loadData is not completed on the server.

You are of course, free to explore and try that approach yourself, but do notice that you'd need to start streaming the server content with renderToPipeableStream and React’s expectation is that the whole HTML is part of React app. Template renders only part of the DOM: the app UI is rendered to a string that is then injected inside public/index.html document.

Read more about streaming:

What about React v19?
React v19 is released a month ago, but not all the dependency libraries support it atm. We don't plan to make v19 update anytime soon, but v18.3.1 is the last version before that major update: it already started to warn about deprecated features (like defaultProps & propTypes). Therefore that update might not be as huge as this one was.

Gnito added 25 commits January 10, 2025 12:42
Note: v7 is just a bug fix (changing unintended async loading to synchronous)
The patch is related to bug in Safari.
Bug: Cannot read property 'active' of undefined
final-form/final-form#186 (comment)
We did not update to the newest (v7.0.1), because there is a bug
with fast-memoize:
formatjs/formatjs#4725
Remove deprecated url.parse in favor of WhatWG URL API
Note: this library does not have proper changelog nor release notes!
Update tests related to path-to-regexp update
- The path params need to be strings
- Thrown errors have been changed
Gnito added 27 commits January 10, 2025 12:42
Todo: classes related to reusable map setup should be untangled at some point.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant