我正在尝试使用Redux和Redux-saga进行React SSR。
我能够使客户端呈现正常工作,但是服务器存储似乎从未获得数据/在呈现HTML之前等待数据。
server.js
import express from 'express';
import renderer from "./helpers/renderer";
import createStore from "./helpers/createStore";
import {matchRoutes} from 'react-router-config';
import Routes from "./client/Routes";
import rootSaga from "./client/saga";
const app = express();
app.use(express.static('public'));
app.get('*', (req, res) => {
const store = createStore();
const branch = matchRoutes(Routes, req.path);
const promises = branch.map(({ route }) => {
return route.loadData ? route.loadData(store) : Promise.resolve(null);
});
store.runSaga(rootSaga).done.then(() => {
res.send(renderer(req, store)) // helper method to load static router and provider
}) // Not required after Update 2 , Promise.All should work ..
});
app.listen(3000, () => {
console.log('Listening on Port 3000');
})
小传奇
import { put, takeEvery, all, call } from 'redux-saga/effects'
import {FETCH_USERS, SAVE_USERS} from "../actions";
import axios from 'axios';
export function* fetchUsers() {
const res = yield call(getUsers);
yield put({ type: SAVE_USERS, payload: res.data});
}
const getUsers = () => {
const response = axios.get('http://react-ssr-api.herokuapp.com/users');
return response;
}
export function* actionWatcher() {
yield takeEvery(FETCH_USERS, fetchUsers)
}
export default function* rootSaga() {
yield all([
actionWatcher()
])
}
错误
TypeError:无法读取未定义的属性'then'在/Users/rahsinwb/Documents/Mine/code/SSR/build/bundle.js:309:39
我在这里想念的是什么?还是有任何经过验证的方式可以侦听故事的结尾,我当时在想我组件中带有store.dispatch
的loadData辅助函数进行初始操作调用会返回promise,但它永远不会起作用。
LoadData
const loadData = (store) => {
store.dispatch({type: FETCH_USERS});
}
更新
将其添加到我的index.js文件中
store.runSaga(rootSaga).toPromise().then(() => {
branch.map(({ route }) => {
return route.loadData ? route.loadData(store) : Promise.resolve(null);
});
res.send(renderer(req, store))
})
现在代码可以正确执行,但是问题是saga从loadData方法即FetchData派发了一个动作,在fetchData在上述的saga中调用Save_DATA动作之前,调用被取消了我的假设,而reducer被留下了。为空,导致html无法加载数据,
我们如何知道生成器的数据加载已完成从启动动作到加载数据动作的功能?到减速器,因为只有我应该在服务器上渲染组件的帖子
Update2
[还检查了lib,但是出于某种奇怪的原因,它引发了再生器问题,但是我不认为lib是出于这样的目的而设计的:我计划为客户端Redux调用重用相同的传奇,并希望保留变化分开了。index.js
console.log(promises); // no promise returned undefined
//setTimeout((function() {res.send(renderer(req, store))}), 2000);
Promise.all(promises).then(
res.send(renderer(req, store))
)
添加设置超时有帮助,我能够在服务器中获取数据,并且然后渲染,所以问题的关键在于,我们需要一些如何等待生成器函数解析然后调用render。
我能够找到一种解决此问题的方法,但这并不是一种干净的解决方案,我也不想为每个loadData方法+ saga都这样做。我能够抽象出它是实现这一目标的一种更干净的方法,因为我对答案仍然不满意
组件中的loadData
const loadData = (store) => {
//store.dispatch({type: FETCH_USERS})
return new Promise((resolve) => {
store.dispatch({type: FETCH_USERS, callback: resolve })
});
}
Saga
function asyncCallBackUtil(action){
if (action.callback) {
action.callback('Done');
}
}
export function* fetchUsers(action) {
const res = yield call(getUsers);
yield put({ type: SAVE_USERS, payload: res.data});
asyncCallBackUtil(action);
}
现在我可以使用帖子中提到的Promise.All
Promise.all(promises).then(data => {
console.log('here',data);
res.send(renderer(req, store))
})
是否有解决此问题的更简便方法,因为我需要为其他问题解决传奇也是。