Skip to content

Add SSRProvider to ensure consistent ids between server and client#992

Merged
dannify merged 3 commits into
mainfrom
ssr-ids
Aug 21, 2020
Merged

Add SSRProvider to ensure consistent ids between server and client#992
dannify merged 3 commits into
mainfrom
ssr-ids

Conversation

@devongovett
Copy link
Copy Markdown
Member

Closes #959
Related: #760, #835, #899, #842

This adds an SSRProvider component that must be used when using React Spectrum or React Aria in a server rendered environment. This lives within the @react-aria/ssr package, and we'll also re-export it from the @adobe/react-spectrum mono-package. useId still lives within @react-aria/utils though for back compatibility, so we had to add a dependency on @react-aria/ssr there.

<SSRProvider>
  <Provider theme={defaultTheme}>
    <App />
  </Provider>
</SSRProvider>

SSRProvider provides a context to the rest of the app containing two numbers: a prefix number, and a current id. By default, when no SSRProvider is available, the prefix is set to a random number. This allows multiple instances of React Spectrum/React Aria to be on the page at once in order to prevent potential id clashes. However, when in an SSR environment we must set this prefix to a known value that will be consistent between the client and server. Therefore, in SSR, only a single copy of React Spectrum/React Aria will be supported. This seems like a reasonable tradeoff.

The second number is the current auto incrementing id that is incremented whenever useId is called. However, rather than being a global value, it's now also in the context. This ensures that the server resets the value for each request, which keeps the ids consistent between the client and server.

The one case where it's possible to get mismatches is with async-loaded components. While React.lazy doesn't support SSR yet, there are other libraries that implement this. If the loading order of these async boundaries were different between the client and server, we could get id mismatches. This can be solved by wrapping each async component in an additional <SSRProvider>. Doing this resets the current id counter, and increments the prefix. This way, the prefix is incremented outside the async boundary, and the ids within the async component are guaranteed to be unique.

<SSRProvider>
  <AsyncComponent />
</SSRProvider>

Finally, I had to update the way the SSR tests ran because they were not capturing the mismatching ids in all cases. That was because Jest resets the environment before each test, so the ids were starting over from zero each time. Now we run a single server to do SSR for all tests over HTTP, and the tests just make requests to it. That better simulates a real long-running server environment.

@adobe-bot
Copy link
Copy Markdown

Build successful! 🎉

@adobe-bot
Copy link
Copy Markdown

Build successful! 🎉

@adobe-bot
Copy link
Copy Markdown

Build successful! 🎉

@dannify dannify merged commit 7e495dd into main Aug 21, 2020
@dannify dannify deleted the ssr-ids branch August 21, 2020 21:11
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.

3 participants