[英]Server Side React Initial Render causes duplicated async calls
我在服务器上使用 react-router 2.0。 我的一些顶级路由组件依赖于要获取的异步数据并使用 Redux 来管理状态。 为了解决这个问题,我使用了一个静态的fetchData()
方法来返回一个Promise.all
的异步操作,如官方 Redux 文档中所建议的。 它工作得很好——来自服务器的初始渲染带有 Redux 存储中的适当数据。
我的问题来自如何编写这些异步调用,这种方式既适用于服务器上的初始渲染,又适用于客户端上的后续渲染,因为加载了不同的路由。 目前,我在顶级组件的componentDidMount()
调用静态fetchData()
方法,但是一旦组件安装在客户端上,这将导致fetchData()
。 这是我从另一个导航到路由时想要的,但不是在初始渲染时,因为我们已经在服务器上进行了这个调用。
我一直在努力以一种方式编写我的数据获取逻辑:
我正在考虑将像{ serverRendered: true }
这样的道具注入初始组件,但在调用renderToString()
时我只能访问<RouterContext>
。 我查看了源代码,但似乎我也无法从该 JSX 标记传递该属性。
我想我的问题是:
<RouterContext>
注入一个属性,以便它向下传递到“父”顶级路由组件? 如果不在<RouterContext>
,是否有另一种方法可以注入该属性?fetchData()
以便初始渲染不会导致fetchData()
在服务器和客户端上都被调用?我遇到了同样的问题。 使用setTimeout
清除某些全局值或检查 Redux 存储中是否存在数据对我来说并不好。
我决定检查加载了哪些路径初始数据,将此数组作为全局值并检查componentDidMount
路由匹配。
我的服务器 index.js
const pathsWithLoadedData= []; // here I store paths
const promises = matchRoutes(Routes, req.path)
.map(({ route }) => {
if (route.loadData) {
// if route loads data and has path then save it
route.path && pathsWithLoadedData.push(route.path);
return route.loadData(store);
} else {
return Promise.resolve(null);
}
})
我的渲染模板
<body>
...
<script>
window.INITIALLY_LOADED_PATHS = ${JSON.stringify(pathsWithLoadedData)};
</script>
...
</body>
一些 componentDidMount 函数
componentDidMount () {
if (!wasFetchedInitially(this.props.route.path)) {
this.props.fetchUsers();
}
}
和帮手
export const wasFetchedInitially = componentPath => {
const pathIndex = window.INITIALLY_LOADED_PATHS.indexOf(componentPath);
if (pathIndex < 0) return false;
window.INITIALLY_LOADED_PATHS.splice(pathIndex, 1);
return true;
};
我注入一个全局变量window.__INITAL_FROM_SERVER__ = true
并从客户端使用setTimeout
清除它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.