You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为React Router 4实现服务端渲染?求教程及代码迁移资源

Hey there! Let's walk through how to migrate your server-side rendering (SSR) code from the older React Router version (used in Pro MERN Stack) to React Router 4. I'll break this down step by step since v4 completely reworked SSR mechanics—goodbye match and RouterContext, hello StaticRouter!

Step 1: Update Dependencies

First, swap out the old react-router package for react-router-dom (v4.x), which now handles all DOM-specific routing logic:

npm uninstall react-router
npm install react-router-dom@4

Step 2: Rewrite Server-Side Rendering Logic

The biggest change is ditching the match function and RouterContext for StaticRouter—a Router built explicitly for server-side use. Here's how to refactor your renderedPageRouter.jsx:

Old Code (From the Book):

import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import routes from './routes';

// Typical Express route handler
app.get('*', (req, res) => {
  match({ routes, location: req.url }, (err, redirectLocation, renderProps) => {
    if (err) {
      res.status(500).send(err.message);
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search);
    } else if (renderProps) {
      const html = renderToString(<RouterContext {...renderProps} />);
      res.send(`<div id="root">${html}</div>`);
    } else {
      res.status(404).send('Not Found');
    }
  });
});

New React Router 4 Code:

import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
// Import your root app component (where you define routes)
import App from './App';

// Updated Express route handler
app.get('*', (req, res) => {
  // Create a context object to capture redirects/404 statuses
  const context = {};

  // Use StaticRouter instead of match + RouterContext
  const html = renderToString(
    <StaticRouter location={req.url} context={context}>
      <App />
    </StaticRouter>
  );

  // Handle redirects captured by the context
  if (context.url) {
    res.redirect(302, context.url);
    return;
  }

  // Handle 404s (set in your NotFound component)
  const statusCode = context.status === 404 ? 404 : 200;
  res.status(statusCode).send(`
    <!DOCTYPE html>
    <html>
      <body>
        <div id="root">${html}</div>
        <script src="/client-bundle.js"></script>
      </body>
    </html>
  `);
});

Step 3: Update Client-Side Routing

On the client, replace the old Router with BrowserRouter:

// client/index.jsx
import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

Step 4: Define Routes in Your App Component

React Router 4 uses component-based routing instead of route arrays. Here's how to structure your App.jsx:

import React from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import Home from './Home';
import About from './About';
import NotFound from './NotFound';

const App = () => (
  <Switch>
    {/* Exact match for home */}
    <Route exact path="/" component={Home} />
    {/* About page */}
    <Route path="/about" component={About} />
    {/* Redirect example */}
    <Redirect from="/old-about" to="/about" />
    {/* Catch-all 404 */}
    <Route component={NotFound} />
  </Switch>
);

export default App;

Step 5: Handle 404 Status on the Server

To let the server know when a 404 occurs, update your NotFound component to set the context status:

import React from 'react';

const NotFound = ({ staticContext }) => {
  // staticContext only exists during SSR
  if (staticContext) {
    staticContext.status = 404;
  }
  return <h1>404 - Page Not Found</h1>;
};

export default NotFound;

Step 6: Data Prefetch (Optional)

If your original code included data prefetching for SSR, you can add static loadData methods to your route components and call them server-side. For simplicity, use the official react-router-config package to streamline this:

  1. Install it:
    npm install react-router-config
    
  2. Define routes as an array:
    // routes.js
    import Home from './Home';
    import About from './About';
    import NotFound from './NotFound';
    
    const routes = [
      {
        path: '/',
        exact: true,
        component: Home,
        loadData: () => fetch('/api/home-data').then(res => res.json())
      },
      {
        path: '/about',
        component: About,
        loadData: () => fetch('/api/about-data').then(res => res.json())
      },
      {
        component: NotFound
      }
    ];
    
    export default routes;
    
  3. Update your server to prefetch data:
    import { matchRoutes } from 'react-router-config';
    import routes from './routes';
    
    app.get('*', async (req, res) => {
      const context = {};
      // Get all matching routes and their data fetch functions
      const matches = matchRoutes(routes, req.url);
      const dataPromises = matches.map(({ route }) => 
        route.loadData ? route.loadData() : Promise.resolve(null)
      );
    
      // Wait for all data to load
      await Promise.all(dataPromises);
    
      // Render with preloaded data
      const html = renderToString(
        <StaticRouter location={req.url} context={context}>
          <App routes={routes} />
        </StaticRouter>
      );
    
      // Send response (same as before)
      if (context.url) {
        res.redirect(302, context.url);
        return;
      }
      const statusCode = context.status === 404 ? 404 : 200;
      res.status(statusCode).send(`<div id="root">${html}</div>`);
    });
    

Key Takeaways

  • No more match/RouterContext: Replace with StaticRouter (server) and BrowserRouter (client)
  • Component-based routing: Routes are now nested components instead of arrays (or use react-router-config for array-based setup)
  • Context object: Captures redirects and status codes for server-side handling
  • Data prefetch: Use static component methods or react-router-config to load data before rendering

内容的提问来源于stack exchange,提问作者Maicmi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:17:48