[英]How to do Server Side Rendering in React With React Loadable and Fetching Data for Components (Like Next.js)?
How Can i have Next.js Like Data Fetching ( getInitialProps ) with React Router and React Loadable using Razzle . 我如何使用反射路由器和使用Razzle React可加载的数据获取( getInitialProps )Next.js。 I had data fetching without react-loadable but without code splitting app bundle is too big and it's taking too long to load the page for clients.
我没有反应加载的数据提取但没有代码拆分应用程序包太大而且为客户端加载页面花费的时间太长。
this code works, but I just don't understand what I did about a year ago (it's a little bit different from the previous example) 这段代码有效,但我只是不明白一年前我做了什么(它与前面的例子略有不同)
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 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)
routes: 路线:
[
{
path: "/",
exact: true,
component: Loadable({
loader: () => import("@views/Home"),
loading: Loading,
}),
},
{
path: "/shop",
exact: true,
component: Loadable({
loader: () => import("@views/Shop"),
loading: Loading,
}),
},
]
My Components are Like This: 我的组件是这样的:
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 Loadable Component have preload() method that can load Component so i tried: route.component.preload()
but it's not working. React可加载组件有preload()方法,可以加载组件,所以我尝试:
route.component.preload()
但它不工作。
I tried loadable-components and it has the same problem with that too but I can replace react-loadable with loadable-components(my preferred library is loadable-components cause it's ok with StrictMode). 我尝试了可加载的组件,它也有同样的问题,但我可以用可加载的组件替换反应加载(我的首选库是可加载组件,因为它可以使用StrictMode)。
actually, after.js solved this problem (it uses Razzle) if I could extract code splitting logic and use it in my app or have some working example of data-fetching and react-loadable together it would be awesome. 实际上, after.js解决了这个问题(它使用Razzle),如果我可以提取代码分裂逻辑并在我的应用程序中使用它,或者有一些数据获取和反应可加载的工作示例,那将是非常棒的。
This is how i did this. 这就是我这样做的方式。
Its working with both. 它与两者合作。 loadable Components and normal components.
可加载组件和普通组件。
Inside matchRoutes(). 里面的matchRoutes()。 check for component.preload.
检查component.preload。
If its true, then allow it to load component.preload(). 如果为true,则允许它加载component.preload()。
This will return a promise And after promise resolves, we will get our component. 这将返回一个承诺。在承诺结算后,我们将获得我们的组件。 Then check for loadData/getInitialProps/fetchData, whatever static method name we are using.
然后检查loadData / getInitialProps / fetchData,无论我们使用什么静态方法名称。
return res.default.loadData ? res.default.loadData(store) : null;
you can call server side fetch request .. i am calling it loadData() 你可以调用服务器端获取请求..我正在调用它loadData()
Always remember to return the promise, because its a chain of promise. 永远记住要回报承诺,因为它是一连串的承诺。
Aslo inside your redux actions, always remember to return the dispatch(). 在你的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.