我正在使用redux-saga实现服务器端呈现。
我正在关注redux-saga存储库中提供的"real world" example。
renderToString
来呈现应用。componentWillMount
,它会调度操作GET_GEOLOCATION
和GET_DATE
。这些异步操作将通过SET_GEOLOCATION
和SET_DATE
解决。renderToString
完成呈现应用程序; END
操作会终止传奇听众问题在于SET_GEOLOCATION
和SET_DATE
本身用于put
新动作GET_MOVIES
。但是,在调用SET_GEOLOCATION
和SET_DATE
时,传奇侦听器不再处于活动状态(我们在renderToString
之后终止它)。因此,在调度GET_MOVIES
时,不会选择GET_MOVIES
操作,SET_MOVIE
将永远不会发生。
服务器代码:
app.get('*', (req, res) => {
const history = createMemoryHistory({
initialEntries: [
req.url
]
});
const store = configureStore(undefined, history);
const context = {};
const rootComponent = <Provider store={store}>
<StaticRouter context={context} location={req.url}>
<Route component={RootRoute} />
</StaticRouter>
</Provider>;
store
.runSaga(rootSaga).done
.then(() => {
const body = renderToString(rootComponent);
const response = renderHtml(body, store);
res
.send(response);
})
.catch((error) => {
res
.status(500)
.send(error.message);
});
// Force componentWillMount to issue saga effects.
renderToString(rootComponent);
store.close();
});
萨加斯:
const watchNewSearchCriteria = function *(): Generator<*, *, *> {
yield takeLatest([
SET_GEOLOCATION,
SET_DATE
], function *() {
const {
coordinates,
date
} = yield select((state) => {
return {
coordinates: state.movieEventsView.location ? state.movieEventsView.location.coordinates : null,
date: state.movieEventsView.date
};
});
if (!coordinates || !date) {
return;
}
yield put(getMovies({
coordinates,
date
}));
});
};
const watchGetMovies = function *() {
yield takeLatest(GET_MOVIES, function *(action) {
const result = yield call(getMovies, action.payload);
yield put(setMovies(result));
});
};
如果没有store.close
以外的州内没有传奇,那么如何推迟take
答案 0 :(得分:4)
如果没有
store.close
以外的州内没有传奇,那么如何推迟take
要回答我自己的问题,我需要观察任何put
的解决方案。我可以使用Saga Monitor。
可以在创建redux-saga
中间件时配置Saga Monitor。对于我们的用例,它需要跟踪某个操作put
,并在解析/拒绝/取消时将其从索引中删除。
const activeEffectIds = [];
const watchEffectEnd = (effectId) => {
const effectIndex = activeEffectIds.indexOf(effectId);
if (effectIndex !== -1) {
activeEffectIds.splice(effectIndex, 1);
}
};
const sagaMiddleware = createSagaMiddleware({
sagaMonitor: {
effectCancelled: watchEffectEnd,
effectRejected: watchEffectEnd,
effectResolved: watchEffectEnd,
effectTriggered: (event) => {
if (event.effect.CALL) {
activeEffectIds.push(event.effectId);
}
}
}
});
我们需要从商店的消费者那里访问它,因此我将activeEffectIds
分配给商店实例:
store.runSaga = sagaMiddleware.run;
store.close = () => {
store.dispatch(END);
};
store.activeEffectIds = activeEffectIds;
然后不是同步停止传奇...
renderToString(rootComponent);
store.close();
我们需要延迟store.close
,直到store.activeEffectIds.length
为0。
const realDone = () => {
setImmediate(() => {
if (store.activeEffectIds.length) {
realDone();
} else {
store.close();
}
});
};
// Force componentWillMount to issue saga effects.
renderToString(rootComponent);
realDone();
现在只有在解决了所有异步效果后才会调用store.close
。