React SSR项目使用@loadable/component出现hydration警告求助
This warning (and the annoying page flicker) is definitely tied to how @loadable/component handles server-side rendering (SSR) out of the box. When you use dynamic code splitting without proper SSR configuration, there’s a mismatch between what the server renders and what the client tries to hydrate initially. Let’s break down why this happens and how to fix it:
Why the Issue Happens
When you use loadable() for dynamic imports:
- On the server, if you don’t explicitly preload the dynamic component,
@loadable/componentwon’t render the actual component content during SSR—it’ll render an empty placeholder (or nothing at all) instead. - On the client, before the dynamic chunk finishes loading, the loadable component also renders a placeholder. Once the chunk loads, it replaces the placeholder with the real component, causing that flicker.
- Even if you think server and client output match, the initial hydration state on the client doesn’t align with what the server sent, triggering React’s strict mismatch warning.
When you switch to direct imports, the component loads synchronously on both server and client, so the rendered HTML matches perfectly from the start—no mismatch, no flicker.
Step-by-Step Fixes
1. Add SSR Support for @loadable/component
First, install the server-side package that handles capturing and preloading dynamic components:
npm install @loadable/server
2. Update Your Server Rendering Code
Modify your server to capture, preload, and sync dynamic components before rendering:
import { LoadableCapture } from '@loadable/server' import { renderToString } from 'react-dom/server' import App from './App' // This file is generated by @loadable/webpack-plugin (see next step) import loadableStats from '../dist/loadable-stats.json' async function renderServerSide(req, res) { // Capture all dynamic components used in the app const capture = new LoadableCapture() // Wrap your app with the capture utility const serverHtml = renderToString( <LoadableCapture capture={capture}> <App /> </LoadableCapture> ) // Preload all captured dynamic components await capture.preloadAll(loadableStats) // Get the loadable state to pass to the client const loadableState = JSON.stringify(capture.getState()) // Inject the state into your HTML template res.send(` <!DOCTYPE html> <html> <body> <div id="root">${serverHtml}</div> <!-- Pass loadable state to client to sync hydration --> <script>window.__LOADABLE_STATE__ = ${loadableState}</script> <script src="/path/to/your/client/bundle.js"></script> </body> </html> `) }
3. Configure Webpack to Generate Loadable Stats
Install the webpack plugin that creates the loadable-stats.json file needed for preloading:
npm install @loadable/webpack-plugin --save-dev
Add it to your webpack config:
const LoadablePlugin = require('@loadable/webpack-plugin') module.exports = { // ... your existing webpack config plugins: [ // ... other plugins new LoadablePlugin(), ], }
4. Adjust Client-Side Hydration
Modify your client entry file to wait for loadable components to be ready before hydrating:
import { loadableReady } from '@loadable/component' import { hydrate } from 'react-dom' import App from './App' // Wait for all dynamic components to load before hydrating loadableReady(() => { hydrate(<App />, document.getElementById('root')) })
Verify the Fix
After implementing these changes:
- The server will preload all dynamic components during SSR, so it renders the actual component content instead of a placeholder.
- The client receives the loadable state, so it knows which components are already loaded and avoids rendering a placeholder during hydration.
- This eliminates the DOM mismatch warning and the page flicker caused by dynamic chunk loading.
内容的提问来源于stack exchange,提问作者Alejandro Garcia Anglada

