如何在Next.js中处理长时间异步操作以避免页面加载缓慢?

时间:2019-07-07 13:41:56

标签: react-redux next.js

使用next-redux-wrapper时,如何启动长时间的异步任务,使其仅在客户端上运行?我不想在服务器端使用await,因为它会延迟初始页面加载。我宁愿在任务开始时设置加载标志,并显示加载指示器,直到任务完成。

假设我的异步操作如下:

function async takesLong(store) {
    store.dispatch({type: “LOADING”, payload: true});
    const result = await longOperation();  
    store.dispatch({type: “SETDATA”}, payload: data);
    return store.dispatch({type: “LOADING”, payload: false});
}

我可以在下一页的getInitialProps函数中调用此命令,

MyPage.getInitialProps = async ({ store, isServer }) => {
  const loader = takesLong(store)
  if (isServer) await loader;   // <-- will delay client response
  return {
    someprop: "some value"
  };
};

如果页面在客户端上加载,则效果很好。该操作开始,并且在操作完成之前,我的页面可以显示加载程序。但是在服务器端上启动时,该页面完全显示之前有很长时间。我尝试了多种方法,但找不到合适的方法:

  1. 在服务器上启动进程而不使用await会呈现页面,而结果不会写入到存储中,因此它仅在存储中将“ loading”设置为true,并且从不获取数据。 / li>
  2. 在我的store中传递props不起作用-它最终在客户端中成为空对象({ })。
  3. 由于某些原因,试图在组件内部运行它似乎无效:

    a)我没有在React组件中访问store对象(仅在getInitialProps中无法在客户端上调用)。

    b)即使我在组件中使用动作代替store.dispatch,何时可以安全地调用它?我无法在render期间执行此操作,因为它将更改Redux状态,并且componentWillReceiveProps在第一个客户端render

  4. 之前不会被调用

使用Next时,是否存在定义明确的模式将长时间操作推迟到客户端?

2 个答案:

答案 0 :(得分:1)

componentDidMount上执行长时间异步任务,它将仅在客户端运行。 SSR中的React无法运行componentDidMount生命周期挂钩。

答案 1 :(得分:1)

componentDidMount期间使用绑定动作有效。感谢@eenagy的建议。按此顺序执行操作似乎可以完成所需的操作:

import { bindActionCreators } from "redux";
import { setLoading, setError, setData } from "../actions";

componentDidMount() {
  if (!this.props.haveData && !this.props.loading && !this.props.error) {
    this.props.setLoading(true);
    loadSomeData()        // <-- this takes a while to complete
      .then( data => {
        this.props.setData(data);
        this.props.setLoading(false);
      })
      .catch( err => {
        this.props.setError(err);
        this.props.setLoading(false);
      });
  }
}

render() {
  if (this.props.loading) return (<Loading/>);
  return (/*regular page*/);
}

export const mapDispatchToProps = dispatch => {
  return bindActionCreators({ setLoading, setError, setData }, dispatch);
};

export default connect(mapStateToProps, mapDispatchToProps)(Component);

这样,如果尚未加载初始数据(例如由另一页加载),则当 组件安装并异步运行,直到操作完成并 调用redux中的操作导致页面重新呈现。