我在服务器上使用react-router 2.0。我的一些顶级路由组件依赖于要获取的异步数据,并使用Redux来管理状态。为了解决这个问题,我使用静态fetchData()
方法返回the official Redux docs中建议的Promise.all
异步操作。它工作得很好 - 服务器的初始渲染带有Redux存储中的相应数据。
我的问题来自如何以一种方式编写这些异步调用,这种方式既可以在服务器上进行初始渲染,也可以在不同路由加载时在客户端上进行后续渲染。目前,我在顶级组件的fetchData()
中调用静态componentDidMount()
方法,但这会导致在组件安装到客户端后调用fetchData()
。这是我在从另一个路由导航到路由时所需要的,但不是在初始渲染上,因为我们已经在服务器上进行了此调用。
我一直在努力以下列方式编写数据获取逻辑:
我在考虑将{ serverRendered: true }
这样的道具注入初始组件,但在调用<RouterContext>
时我只能访问renderToString()
。我看了一眼源代码,但似乎我不能从JSX标签传递属性。
我想我的问题是:
<RouterContext>
中注入一个属性,以便传递给'父'顶层路由组件?如果不在<RouterContext>
,是否有其他方式注入该属性? fetchData()
,因此初始渲染不会导致在服务器和客户端上调用fetchData()
?答案 0 :(得分:1)
我面临着同样的问题。用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;
};
答案 1 :(得分:0)
我注入了一个全局变量window.__INITAL_FROM_SERVER__ = true
,并从客户端用setTimeout
清除了该变量。