ReactJS服务器端渲染,Settimeout问题



在我的reactjs应用程序上,我使用 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 Action Chain的一部分。它运行良好,但是当我试图使此功能成为服务器端渲染过程的一部分时,它会破坏该应用程序。我了解浏览器和nodejs运行时环境之间的区别以及其setTimeout实现之间的差异。具体来说,由于它是一个对象,因此无法通过节点处理我的timerId,而我的Redux还原器将其视为整数。但是主要的问题是,在服务器端渲染节点在服务器端触发setTimeout回调...

问题。我有一些基于REDUX的Proccess,在某些情况下应该推迟使用,包括应用程序启动。我该如何满足服务器端渲染的要求?

在进行一些研究之后,我能够采用以下方法。

1)在服务器端渲染的情况下,将延迟的操作数据推入某些特殊存储,并在浏览器的情况下按照"原样"运行:

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具有以下实体:

// to run actions on the Client after server-side rendering
export const _postRender = { actions: [] }; 

2)在我导入的服务器上,当所有redux商店数据依赖项都解决时,我导入的_postRender对象表单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);

_postRender.actions必须清理,否则每次重新加载客户端时,P.1的_postRender.actions.push都会一次又一次填充。

3)然后,我以与预加载状态相同的方式提供了渲染后的操作。就我而言,是index.ejs模板:

<div id="main"><%- markup %></div>
<script>
  var __PRELOADED_STATE__ = <%- JSON.stringify(finalState) %>;
  var __POST_RENDER__ = <%- JSON.stringify(postRender) %>;
</script>

4)现在我需要用给定参数调用我的__POST_RENDER__操作。为此,我更新了我的根部组件的diD-mount钩子,并派遣了处理渲染后操作列表的其他操作:

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导入:

import { doLockSide } from './topic'
export const runAfterRender = (list) => (dispatch) => {
  list.forEach(action => {
    if(action.name === 'doLockSide') {
      dispatch(doLockSide(action.params));
    }
    // other actions?
  });
};

您可以看到,这只是一份草稿,我被迫从第1页进口doLockSide操作,并明确称其为称。我想在服务器端渲染后可能会在客户端上调用可能的操作列表,但是此方法已经有效。我想知道是否有更好的方法...

最新更新