1

我想要做的是提高单击时 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;
4

1 回答 1

-1

嗨,我可以提供一些建议。

  1. 检查调用组件的 api。改进您的 api 方法以获得更快的响应。
  2. 删除组件中不必要的使用或改进它。
  3. 如果您调用数据库,请检查您的查询。
  4. 您可以调试它的后端并找出您浪费时间的地方。
  5. 对于前端,改进您的组件。
于 2020-05-25T20:09:17.830 回答