繁体   English   中英

如何使用React可加载和获取组件数据(如Next.js)进行服务器端渲染?

[英]How to do Server Side Rendering in React With React Loadable and Fetching Data for Components (Like Next.js)?

我如何使用反射路由器和使用Razzle React可加载的数据获取( getInitialProps )Next.js。 没有反应加载的数据提取但没有代码拆分应用程序包太大而且为客户端加载页面花费的时间太长。

这段代码有效,但我只是不明白一年前我做了什么(它与前面的例子略有不同)

    const promises = routes
        .map((route) => {
            const match = matchPath(req.url, route)
            if (match && route.component) {
                let promise

                if (typeof route.component.preload === "function") {
                    promise = route.component.preload()
                } else {
                    promise = Promise.resolve(route.component)
                }

                return promise
                    .then((res) => {
                        return res && res.__esModule ? res.default : res
                    })
                    .then((component) => {
                        let promises = []

                        // STATIC INTI ACTION
                        promises.push(store.dispatch(getToken()))

                        if (component.initialAction) {
                            let results = component.initialAction({ match })

                            results = Array.isArray(results)
                                ? results
                                : [results]
                            results.forEach((result) => {
                                promises.push(store.dispatch(result))
                            })
                        }
                        return promises
                    })
            }

            return null
        })
        .filter((el) => el !== null)

    // page not found
    if (promises.length === 0) {
        renderTree(req, res, store)
    } else {
        Promise.all(promises.map((data) => data.then((moreData) => moreData)))
            .then((data) => {
                Promise.all(data[0]).then(() => renderTree(req, res, store))
            })

Server.js

const promises = []

routes.some((route) => {
    const match = matchPath(req.url, route);
    if (match) {
        // route.component is React Loadable Component so getInitialData is undefined
        if (route.component.getInitialData) {
            promises.push(route.component.getInitialData({ match, req, res }))
        }
        return true;
    }
    return false;
});

Promise.all(promises)
    .then(renderReact)
    .catch(handleError)

// and at the end i will call
Loadable.preloadAll()
  .then(sendResponseToUser)

路线:

[
    {
        path: "/",
        exact: true,
        component: Loadable({
            loader: () => import("@views/Home"),
            loading: Loading,
        }),
    },
    {
        path: "/shop",
        exact: true,
        component: Loadable({
            loader: () => import("@views/Shop"),
            loading: Loading,
        }),
    },
]

我的组件是这样的:

class Home extends React.Component {
  // This works similarly to Next.js's `getInitialProps`
  static getInitialData({ match, req, res }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve({
          text: `
This text is server rendered if and only if it's the initial render.
Go to another route.
          `,
          currentRoute: match.pathname,
        });
      }, 500);
    });
  }

  render() {
    return <p>this is just a test</p>
  }

}

React可加载组件有preload()方法,可以加载组件,所以我尝试: route.component.preload()但它不工作。

我尝试了可加载的组件,它也有同样的问题,但我可以用可加载的组件替换反应加载(我的首选库是可加载组件,因为它可以使用StrictMode)。

实际上, after.js解决了这个问题(它使用Razzle),如果我可以提取代码分裂逻辑并在我的应用程序中使用它,或者有一些数据获取反应可加载的工作示例,那将是非常棒的。

这就是我这样做的方式。

它与两者合作。 可加载组件和普通组件。

里面的matchRoutes()。 检查component.preload。

如果为true,则允许它加载component.preload()。

这将返回一个承诺。在承诺结算后,我们将获得我们的组件。 然后检查loadData / getInitialProps / fetchData,无论我们使用什么静态方法名称。

return res.default.loadData ? res.default.loadData(store) : null;

你可以调用服务器端获取请求..我正在调用它loadData()

永远记住要回报承诺,因为它是一连串的承诺。

在你的redux动作中,总是记得返回dispatch()。

 app.get('*', (req, res) => { // store instance for every incoming request const store = createStore(req); // loadData from api... before rendering const promises = matchRoutes(Routes, req.path) .map((comp) => { console.log(comp, comp.route.component.loadData) if (comp.route.component.preload){ console.log("LoadableComponent") comp.route.component.preload().then(res => { return res.default.loadData ? res.default.loadData(store) : null; }) } return comp.route.component.loadData ? comp.route.component.loadData(store) : null; }) .map(promise => { if (promise) { return new Promise((resolve, reject) => { promise.then(resolve).catch(resolve); }); } }); Promise.all(promises).then(() => { console.log(store.getState()) const context = {}; const content = renderer(req, store, context); if (context.url) { return res.redirect(301, context.url); } if (context.notFound) { res.status(404); } Loadable.preloadAll().then(() => { res.send(content); }); }); }); 

暂无
暂无

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

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