ReactJS服务器端渲染,setTimeout问题

时间:2017-12-17 13:36:48

标签: javascript reactjs redux settimeout serverside-rendering

在我的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。我怎样才能满足服务器端渲染的要求?

1 个答案:

答案 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? }); }; 动作并明确地调用它。我想在服务器端渲染之后可能会在客户端上调用可能的操作列表,但这种方法已经有效。我想知道是否有更好的方法...