React SSR应用:如何区分hydrate/render渲染及服务端与浏览器渲染?
Hey there! Let’s break down your two React SSR questions with practical, actionable solutions:
1. Detecting if Hydrate or Render is Used
React doesn’t expose a built-in property to directly check if you’re using hydrate or render, but you can implement reliable checks with these approaches:
Check for SSR-rendered DOM content
Before initializing React on the client, inspect your root container. If it has existing child elements (from server-side rendering), usehydrate; otherwise, userender. Here’s a code example:import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; const rootElement = document.getElementById('root'); if (rootElement.hasChildNodes()) { // SSR content exists, use hydrate const root = ReactDOM.hydrateRoot(rootElement, <App />); } else { // No SSR content, use render const root = ReactDOM.createRoot(rootElement); root.render(<App />); }Add a custom SSR marker attribute
When rendering on the server, add a custom data attribute to your root element (e.g.,data-ssr="true"). Then check for this attribute on the client:
Server-side (e.g., with Express):// Server render logic const html = ReactDOMServer.renderToString(<App />); res.send(` <!DOCTYPE html> <html> <body> <div id="root" data-ssr="true">${html}</div> </body> </html> `);Client-side:
const rootElement = document.getElementById('root'); const isSSR = rootElement.getAttribute('data-ssr') === 'true'; if (isSSR) { ReactDOM.hydrateRoot(rootElement, <App />); } else { ReactDOM.createRoot(rootElement).render(<App />); }
2. Differentiating Server vs Browser Execution
To run code only on the server or only in the browser, use these proven methods:
Check for browser-specific globals
The simplest way is to check ifwindowexists (since it’s only available in browsers):function MyComponent() { if (typeof window !== 'undefined') { // This code runs only in the browser console.log('Running in browser'); } else { // This code runs only on the server console.log('Running on server'); } return <div>Hello World</div>; }Use React lifecycle hooks/effects
Client-side-only hooks likeuseEffect(orcomponentDidMountfor class components) don’t execute during server rendering. Perfect for code that relies on browser APIs:import { useEffect } from 'react'; function ClientOnlyComponent() { useEffect(() => { // Runs ONLY in the browser after hydration const timer = setInterval(() => console.log('Tick'), 1000); return () => clearInterval(timer); }, []); return <div>Client-only content</div>; }Custom environment variables
Set a variable during build/execution to flag the environment. For example, in your Node.js server:// Server-side: Set IS_BROWSER to false global.IS_BROWSER = false;In your client-side build config (e.g., Webpack/Vite), define:
// Client-side: Set IS_BROWSER to true define: { IS_BROWSER: true }Then use it in your components:
if (IS_BROWSER) { // Browser-only logic } else { // Server-only logic }Route-specific differentiation
Use React Router’sStaticRouterfor server rendering andBrowserRouterfor the client:
Server-side:import { StaticRouter } from 'react-router-dom/server'; const html = ReactDOMServer.renderToString( <StaticRouter location={req.url}> <App /> </StaticRouter> );Client-side:
import { BrowserRouter } from 'react-router-dom'; ReactDOM.hydrateRoot( document.getElementById('root'), <BrowserRouter> <App /> </BrowserRouter> );
内容的提问来源于stack exchange,提问作者sunknudsen

