在我的ReactJS App上,我使用setTimeout
推迟了一些Redux操作:
export const doLockSide = (lockObject) => (dispatch) => {
const timerId = setTimeout(() => {
dispatch({
type: CONSTANTS.TOPICS_SET_CURRENT_TOPIC_LOCKED_SIDE,
payload: { id: lockObject.topicId, side: lockObject.side, locked: false }
});
}, lockObject.unlockTimeout);
dispatch({
type: CONSTANTS.TOPICS_SET_CURRENT_TOPIC_LOCKED_SIDE,
payload: { id: lockObject.topicId, side: lockObject.side, timerId, locked: true }
});
};
lockObject
来自服务器,因此此代码是异步Redux操作链的一部分。它工作正常,但当我试图使这个功能成为服务器端渲染过程的一部分时,它破坏了应用程序。我理解Browser和NodeJS运行时环境之间的区别以及它的setTimeout
实现之间的区别。具体来说,我的timerId
由于它是一个对象而无法由Node处理,而我的Redux reducer将其视为一个整数。但主要问题是在服务器端渲染期间,Node会在服务器端触发setTimeout
回调...
问题。我有一些基于redux的进程,在某些情况下应该推迟,包括App start。我怎样才能满足服务器端渲染的要求?
答案 0 :(得分:0)
经过一些研究后,我能够应用以下方法。
1)在服务器端呈现的情况下将延迟的操作数据推送到某个特殊存储中,然后运行它"按原样#34;在浏览器的情况下:
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
import { _postRender } from '../utils/misc';
const doLockSideUI = (dispatch, lockObject) => {
// the body of previous version of doLockSide inner function
const timerId = setTimeout(() => {/*...*/}, lockObject.unlockTimeout);
dispatch(/*...*/);
};
export const doLockSide = (lockObject) => (dispatch) => {
if(typeof window === 'undefined') { // server-side rendering case
_postRender.actions.push({
name: 'doLockSide',
params: lockObject
});
}
else { // Browser case
doLockSideUI(dispatch, lockObject);
}
};
具有以下实体:
utils/misc.js
2)在服务器上,我已导入// to run actions on the Client after server-side rendering
export const _postRender = { actions: [] };
对象表单_postRender
,并在所有redux-store数据时将其推送到utils/misc.js
个参数依赖关系已经解决:
render
必须清除 const markup = renderToString(/*...*/);
const finalState = store.getState();
const params = { markup, finalState, postRender: { ..._postRender } };
_postRender.actions = []; // need to reset post-render actions
return res.status(status).render('index', params);
,否则每次重新加载客户端时,p.1中的_postRender.actions
将一次又一次地填充它。
3)然后我提供的渲染后动作的方式与预加载状态相同。就我而言,它是_postRender.actions.push
模板:
index.ejs
4)现在我需要用给定的参数调用我的<div id="main"><%- markup %></div>
<script>
var __PRELOADED_STATE__ = <%- JSON.stringify(finalState) %>;
var __POST_RENDER__ = <%- JSON.stringify(postRender) %>;
</script>
动作。为此,我更新了我的根组件的挂载挂钩,并调度了一个处理后渲染操作列表的附加操作:
__POST_RENDER__
componentDidMount() {
console.log('The App has been run successfully');
if(window.__POST_RENDER__ && window.__POST_RENDER__.actions.length) {
this.props.dispatch(runAfterRender(window.__POST_RENDER__.actions));
}
}
是从runAfterRender
导入的新操作:
../actions/render
正如您所看到的,它只是一个草稿,我被迫从p.1导入import { doLockSide } from './topic'
export const runAfterRender = (list) => (dispatch) => {
list.forEach(action => {
if(action.name === 'doLockSide') {
dispatch(doLockSide(action.params));
}
// other actions?
});
};
动作并明确地调用它。我想在服务器端渲染之后可能会在客户端上调用可能的操作列表,但这种方法已经有效。我想知道是否有更好的方法...