react-router-dom v6 StaticRouter 上下文不工作

react-router-dom v6 StaticRouter context is not working

我正在尝试制作 SSR React 网络应用程序。 除 staticContext 外一切正常。

我的服务器代码是

// IMPORTS

const renderer = (req, store, context) => {
    const content = renderToString(
        <Provider store={store}>
            <ThemeProvider theme={responsiveFontSizes(theme)}>
                <CssBaseline />
                <StaticRouter location={req.path} context={context}>
                    <Navigation />
                    <main>
                        {renderRoutes(MainRouter)}
                    </main>
                    <Footer />
                </StaticRouter>
            </ThemeProvider>
        </Provider>
    );

    const helmet = Helmet.renderStatic();

    return `
        <!DOCTYPE html>
        <html>
            <head>
                <meta charset="utf-8" />
                <link rel="icon" href="${process.env.REACT_APP_URL}/favicon.ico" />
                <meta name="viewport" content="width=device-width, initial-scale=1" />
                <meta name="theme-color" content="${process.env.REACT_APP_THEME_COLOR}" />
                ${helmet.title.toString()}
                ${helmet.meta.toString()}
                <link rel="stylesheet" href="main.css">
                <link rel="preconnect" href="https://fonts.googleapis.com">
                <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
                <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
            </head>
            <body>
                <noscript>Pre dokonalé fungovanie tejto webovej aplikácie povoľte JavaScript.</noscript>
                <div id="root">${content}</div>
                <script>
                    window.INITIAL_STATE = ${serialize(store.getState())}
                </script>
                <script src="bundle.js"></script>
            </body>
        </html>
    `;
};

app.get('*', (req, res) => {

    const store = createStore();

    var promises = matchRoutes(MainRouter, req.path).map(route => {
    return route?.loadData ? route.loadData(store) : [];
    });

    promises.push(loadData(store, req.cookies));

    Promise.all(promises).then(() => {
        const context = {};
        const content = renderer(req, store, context);

        if(context.url) {
            return res.redirect(302, context.url);
        }

        if(context.notFound) {
            console.log('404');
            res.status(404);
        };

        res.send(content);
    });
});

而我的404组件客户端代码是

const NotFound = ({ staticContext = {} }) => {
    staticContext.notFound = true;

    const head = () => (
        <Helmet>
            <title>{process.env.REACT_APP_NAME} – Stránka sa nenašla</title>
        </Helmet>
    );

    return (
        <React.Fragment>
            {head()}
            <section>
                {/* Some content */}
            </section>
        </React.Fragment>
    )
};

export default {
    Component: NotFound
};

此行应将 notFound = true 参数传递到请求中:

staticContext.notFound = true;


因此这部分代码应将请求状态设置为 404 并将控制台日志设置为“404”字符串:

if(context.notFound) {
    console.log('404');
    res.status(404);
};

但是没用。 我的代码是否有可能被弃用? 我正在使用所有依赖项的当前最新稳定版本。

我的 package.json 依赖项

"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@mui/icons-material": "^5.2.5",
"@mui/material": "^5.2.5",
"axios": "0.24.0",
"babel-cli": "6.26.0",
"babel-core": "6.26.3",
"babel-loader": "8.2.3",
"compression": "1.7.4",
"concurrently": "6.5.1",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"date-fns": "^2.27.0",
"express": "4.17.2",
"lodash": "4.17.21",
"nodemon": "2.0.15",
"npm-run-all": "4.1.5",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-helmet": "6.1.0",
"react-redux": "^7.2.6",
"react-router-dom": "6.2.1",
"react-spinners": "^0.11.0",
"redux": "^4.1.2",
"serialize-javascript": "6.0.0",
"universal-cookie": "^4.0.4",
"webpack": "5.65.0",
"webpack-dev-server": "4.7.1",
"webpack-merge": "5.8.0",
"webpack-node-externals": "3.0.0"

Is it possible that my code is deprecated?

恐怕是。

这是 v6.0.0-alpha.4 的主要变化之一:

Removed the <StaticRouter context> API. We don't support navigation on the initial render in v6, so this API is unnecessary.

我最终将状态代码和重定向 URL 存储在 Redux 存储中,并在渲染后在渲染服务器上检查它们。

对于状态代码,我在 NotFound 页面组件的 loadData 函数中调度了 setStatus(404) 操作。

这是我的重定向解决方案 URL:

// router.js

import {useRoutes} from 'react-router-dom';

import getRoutes from '@client/router/routes';
import {useAuthSelector} from '@client/store/slices/auth';

export default ({ssr = false}) => {
  const {currentUser} = useAuthSelector();

  return useRoutes(getRoutes(currentUser, ssr));
};
// routes.js

import requireAuth from './requireAuth';
import App from '@client/App';
import Home from '@client/pages/Home';
import Users from '@client/pages/Users';
import Admins from '@client/pages/Admins';
import NotFound from '@client/pages/NotFound';

export default (currentUser = false, ssr = false) => {
  const protectedRoute = requireAuth(currentUser, ssr);

  return [
    {
      ...App,
      children: [
        {
          path: '/',
          ...Home,
        },
        {
          path: '/users',
          ...Users,
        },
        {
          path: '/admins',
          ...protectedRoute(Admins),
        },
        {path: '*', ...NotFound},
      ],
    },
  ];
};
// requireAuth.js

import React from 'react';
import {Navigate} from 'react-router-dom';

import {setRedirectUrl} from '@client/store/slices/http';

export default (currentUser, ssr = false) => (component) => {
  switch (currentUser) {
    case false:
      if (ssr) {
        // If the user is not logged in and the SSR is happening
        const loadData = component.loadData;

        component.loadData = (store) => {
          // Call the original loadData if component has one
          loadData && loadData(store);
          store.dispatch(setRedirectUrl('/'));
        };
      } else {
        // If the user is not logged in
        component.element = <Navigate to='/' replace />;
      }
      break;

    case null:
      component.element = <div>Loading...</div>;
      break;

    default:
      return component;
  }

  return component;
};

当我在渲染服务器上使用我的路由器时,我只是将 ssr 属性设置为 true。

想到的另一种方法是使用 React 上下文而不是 Redux 存储。

我在使用 SSR 的 StaticRouter 时遇到一般性导入错误,并从 Google 登陆此页面(粘贴错误时)。如果其他人有类似的问题,似乎在 react-router-dom v6 中 StaticRouter 现在应该从 react-router-dom/server.

导入