繁体   English   中英

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

[英]react-router-dom v6 StaticRouter context is not working

我正在尝试制作 SSR React web 应用程序。 除了 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"

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

我也有同样的问题,请问你解决了吗?

我的代码有可能被弃用吗?

恐怕是。

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

删除了<StaticRouter context> API。 我们在 v6 中不支持在初始渲染上导航,所以这个 API 是不必要的。

我最终将状态代码存储在 Redux 存储中,并在NotFound页面组件的loadData function 中调度setStatus(404)操作。 但我不确定这是否可以应用于您的案例,存储重定向 URL。

想到的另一种方法是使用 React 上下文并将上下文值(您传递给您的renderer )提供给NotFound页面组件。

从 v6 开始, <StaticRouter context>将不再可用。 但是,这很容易修复。 您应该改用React Context

首先,您必须创建StaticContext.js文件:

import { createContext, useContext } from 'react';

const StaticContext = createContext({});

const StaticProvider = ({ children, value }) => (
    <StaticContext.Provider value={value}>
        {children}
    </StaticContext.Provider>
);

const useStaticContext = () => useContext(StaticContext);

export { StaticProvider, useStaticContext };

默认情况下,该文件将设置空上下文数据 ( {} )。 然后,您应该在服务器渲染中使用StaticContext.Provider在应用程序之间共享它:

import { StaticProvider } from './contexts/StaticContext';
// ...
const context = {};

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

首先,您必须设置上下文 object 并将其传递给 StaticProvider 元素。 然后将您的应用程序包装到它上面。 稍后,您应该使用useStaticContext function 从上下文中获取和操作数据:

import { useStaticContext } from '../contexts/StaticContext';
import 'react';

export default function NotFoundPage() {
    const context = useStaticContext();
    context.notFound = true;
}

最后一件事,您可以使用context.notFound访问服务器上的上下文变量。

您可以使用 ThemeProvider 来处理未找到的页面。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM