我想要做的是提高单击时 React 路由器加载组件的速度,现在显示它大约需要 1 秒,我希望它像其他较轻的组件一样单击后几乎立即显示。然而,这个组件内部嵌套了 3 个其他大组件,这可能是它加载速度比平时慢的原因吗?
我想要实现的目标: - 预加载组件或预安装,以某种方式预渲染它,以便当我单击路由器链接时 - 它几乎立即显示所需的大组件,就像其他不太重的组件一样。
到目前为止尝试过:使用 React.lazy 进行延迟加载和预加载 https://hackernoon.com/lazy-loading-and-preloading-components-in-react-16-6-804de091c82d
不幸的是,我的应用程序是 SSR 服务器端,并且服务器端反应应用程序不支持 React.lazy。
请告知我应该怎么做才能达到预期的结果?
非常感谢!!!伊万
这是 server.js
/**
* React Starter Kit (https://www.reactstarterkit.com/)
*
* Copyright © 2014-present Kriasoft, LLC. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE.txt file in the root directory of this source tree.
*/
import path from 'path';
import express from 'express';
import cookieParser from 'cookie-parser';
import bodyParser from 'body-parser';
import nodeFetch from 'node-fetch';
import React from 'react';
import ReactDOM from 'react-dom/server';
import PrettyError from 'pretty-error';
import App from './components/App';
import Html from './components/Html';
import { ErrorPageWithoutStyle } from './routes/special/error/ErrorPage';
import errorPageStyle from './routes/special/error/ErrorPage.css';
import createFetch from './createFetch';
import router from './router';
// import assets from './asset-manifest.json'; // eslint-disable-line import/no-unresolved
import chunks from './chunk-manifest.json'; // eslint-disable-line import/no-unresolved
import configureStore from './store/configureStore';
import { setRuntimeVariable } from './actions/runtime';
import config from './config';
const compression = require('compression');
process.on('unhandledRejection', (reason, p) => {
console.error('Unhandled Rejection at:', p, 'reason:', reason);
// send entire app down. Process manager will restart it
process.exit(1);
});
//
// Tell any CSS tooling (such as Material UI) to use all vendor prefixes if the
// user agent is not known.
// -----------------------------------------------------------------------------
global.navigator = global.navigator || {};
global.navigator.userAgent = global.navigator.userAgent || 'all';
const app = express();
//
// If you are using proxy from external machine, you can set TRUST_PROXY env
// Default is to trust proxy headers only from loopback interface.
// -----------------------------------------------------------------------------
app.set('trust proxy', config.trustProxy);
//
// Register Node.js middleware
// -----------------------------------------------------------------------------
app.use(express.static(path.resolve(__dirname, 'public')));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//
// Register server-side rendering middleware
// -----------------------------------------------------------------------------
app.get('*', async (req, res, next) => {
/* if(req.url.includes("sset"))
return next(); */
try {
const css = new Set();
// Enables critical path CSS rendering
// https://github.com/kriasoft/isomorphic-style-loader
const insertCss = (...styles) => {
// eslint-disable-next-line no-underscore-dangle
styles.forEach(style => css.add(style._getCss()));
};
// Universal HTTP client
const fetch = createFetch(nodeFetch, {
baseUrl: config.api.serverUrl,
cookie: req.headers.cookie,
});
const initialState = {
user: req.user || null,
};
const store = configureStore(initialState, {
fetch,
// I should not use `history` on server.. but how I do redirection? follow universal-router
});
store.dispatch(
setRuntimeVariable({
name: 'initialNow',
value: Date.now(),
}),
);
// Global (context) variables that can be easily accessed from any React component
// https://facebook.github.io/react/docs/context.html
const context = {
insertCss,
fetch,
// The twins below are wild, be careful!
pathname: req.path,
query: req.query,
// You can access redux through react-redux connect
store,
storeSubscription: null,
};
const route = await router.resolve(context);
console.log("inside server")
if (route.redirect) {
res.redirect(route.status || 302, route.redirect);
return;
}
const data = { ...route };
data.children = ReactDOM.renderToString(
<App context={context}>{route.component}</App>,
);
data.styles = [{ id: 'css', cssText: [...css].join('') }];
const scripts = new Set();
const addChunk = chunk => {
if (chunks[chunk]) {
chunks[chunk].forEach(asset => scripts.add(asset));
} else if (__DEV__) {
throw new Error(`Chunk with name '${chunk}' cannot be found`);
}
};
addChunk('client');
if (route.chunk) addChunk(route.chunk);
if (route.chunks) route.chunks.forEach(addChunk);
data.scripts = Array.from(scripts);
data.app = {
apiUrl: config.api.clientUrl,
state: context.store.getState(),
};
const html = ReactDOM.renderToStaticMarkup(<Html {...data} />);
res.status(route.status || 200);
res.send(`<!doctype html>${html}`);
} catch (err) {
next(err);
}
});
//
// Error handling
// -----------------------------------------------------------------------------
const pe = new PrettyError();
pe.skipNodeFiles();
pe.skipPackage('express');
// eslint-disable-next-line no-unused-vars
app.use((err, req, res, next) => {
console.error(pe.render(err));
const html = ReactDOM.renderToStaticMarkup(
<Html
title="Internal Server Error"
description={err.message}
styles={[{ id: 'css', cssText: errorPageStyle._getCss() }]} // eslint-disable-line no-underscore-dangle
>
{ReactDOM.renderToString(<ErrorPageWithoutStyle error={err} />)}
</Html>,
);
res.status(err.status || 500);
res.send(`<!doctype html>${html}`);
});
//
// Launch the server
// -----------------------------------------------------------------------------
if (!module.hot) {
app.listen(config.port, () => {
console.info(`The server is running at http://localhost:${config.port}/`);
});
}
//
// Hot Module Replacement
// -----------------------------------------------------------------------------
if (module.hot) {
app.hot = module.hot;
module.hot.accept('./router');
}
export default app;
这里是路由器
/**
* React Starter Kit (https://www.reactstarterkit.com/)
*
* Copyright © 2014-present Kriasoft, LLC. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE.txt file in the root directory of this source tree.
*/
/* eslint-disable global-require */
// The top-level (parent) route
const routes = {
path: '',
// Keep in mind, routes are evaluated in order
children: [
require('./member/invoices/new').default,
{
path: '',
load: () => import(/* webpackChunkName: 'auth' */ './auth/login'),
},
{
path: '/invoices',
children: [
{
path: '',
load: () =>
import(/* webpackChunkName: 'member' */ './member/invoices'),
},
{
path:
'/:id' /*
action: context => `Welcome, ${context.params.id}!` */,
load: () =>
import(
/* webpackChunkName: 'member' */ './member/invoices/preview'
),
},
{
path: '/:id/edit',
load: () =>
import(/* webpackChunkName: 'member' */ './member/invoices/edit'),
},
],
},
{
path: '/quotes',
children: [
{
path: '',
load: () =>
import(/* webpackChunkName: 'member' */ './member/quotes'),
},
{
path: '/new',
load: () =>
import(/* webpackChunkName: 'member' */ './member/quotes/new'),
},
{
path:
'/:id' /*
action: context => `Welcome, ${context.params.id}!` */,
load: () =>
import(/* webpackChunkName: 'member' */ './member/quotes/preview'),
},
{
path: '/:id/edit',
load: () =>
import(/* webpackChunkName: 'member' */ './member/quotes/edit'),
},
],
},
{
path: '/clients',
children: [
{
path: '',
load: () =>
import(/* webpackChunkName: 'member' */ './member/clients'),
},
{
path: '/new',
load: () =>
import(/* webpackChunkName: 'member' */ './member/clients/new'),
},
{
path: '/:id/edit',
load: () =>
import(/* webpackChunkName: 'member' */ './member/clients/edit'),
},
],
},
{
path: '/items',
children: [
{
path: '',
load: () => import(/* webpackChunkName: 'member' */ './member/items'),
},
{
path: '/new',
load: () =>
import(/* webpackChunkName: 'member' */ './member/items/new'),
},
{
path: '/:id/edit',
load: () =>
import(/* webpackChunkName: 'member' */ './member/items/edit'),
},
],
},
{
path: '/settings',
load: () => import(/* webpackChunkName: 'member' */ './member/settings'),
},
{
path: '/billing',
load: () => import(/* webpackChunkName: 'member' */ './member/billing'),
},
{
path: '',
load: () => import(/* webpackChunkName: 'member' */ './member/dashboard'),
},
{
path: '/subscription',
children: [
{
path: '',
load: () =>
import(/* webpackChunkName: 'member' */ './member/subscription'),
},
],
},
{
path: '/auth',
children: [
{
path: '/login',
load: () => import(/* webpackChunkName: 'auth' */ './auth/login'),
},
{
path: '/login/:token',
load: () => import(/* webpackChunkName: 'auth' */ './auth/login'),
},
{
path: '/register',
load: () => import(/* webpackChunkName: 'auth' */ './auth/register'),
},
{
path: '/invoices2',
load: () =>
import(/* webpackChunkName: 'auth' */ './member/invoices'),
},
],
},
{
path: '/admin',
children: [
{
path: '',
load: () => import(/* webpackChunkName: 'admin' */ './admin'),
},
],
},
{
path: '/legal-notice',
load: () =>
import(/* webpackChunkName: 'special-page' */ './special/legal'),
},
{
path: '/privacy-policy',
load: () =>
import(/* webpackChunkName: 'special-page' */ './special/privacy'),
},
{
path: '/refund-policy',
load: () =>
import(/* webpackChunkName: 'special-page' */ './special/refund'),
},
{
path: '/terms-and-conditions',
load: () =>
import(/* webpackChunkName: 'special-page' */ './special/terms'),
},
// Wildcard routes, e.g. { path: '(.*)', ... } (must go last)
{
path: '(.*)',
load: () =>
import(/* webpackChunkName: 'not-found' */ './special/not-found'),
},
],
async action({ next }) {
// Execute each child route until one of them return the result
const route = await next();
console.log(route);
// Provide default values for title, description etc.
route.title = `${route.title || 'Untitled Page'} - sAAsTr`;
route.description = route.description || '';
return route;
},
};
// The error page is available by permanent url for development mode
if (__DEV__) {
routes.children.unshift({
path: '/error',
action: require('./special/error').default,
});
}
export default routes;