【问题标题】:NextJS official sample code: _app.getInitialProps calls Component.getInitialProps -- is this to make sure all pages load data?NextJS 官方示例代码:_app.getInitialProps 调用 Component.getInitialProps ——这是为了确保所有页面都加载数据吗?
【发布时间】:2023-09-11 11:05:01
【问题描述】:

我正在尝试了解如何将 redux-saga 连接到 NextJS,并遵循他们提供的示例代码 -- https://github.com/zeit/next.js。我知道可以从getInitialProps 中加载数据,但我不明白调用Component.getInitialProps 发生了什么:

class MyApp extends App {
  static async getInitialProps({Component, ctx}) {
    let pageProps = {}
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps({ctx})
    }

    return {pageProps}
  }

  render() {
    const {Component, pageProps, store} = this.props
    return (
      <Container>
        <Provider store={store}>
          <Component {...pageProps} />
        </Provider>
      </Container>
    )
  }
}

export default withRedux(createStore)(withReduxSaga({async: true})(MyApp))

这是否允许加载页面的 getIntialProps 中的所有异步加载?也就是说,在index.js我们有代码

class Index extends React.Component {
  static async getInitialProps (props) {
    const { store, isServer } = props.ctx
    store.dispatch(tickClock(isServer))

    if (!store.getState().placeholderData) {
      store.dispatch(loadData())
    }

    return { isServer }
  }

  componentDidMount () {
    this.props.dispatch(startClock())
  }

  render () {
    return <Page title='Index Page' linkTo='/other' NavigateTo='Other Page' />
  }
}

thisgetInitialProps 会等到所有数据加载完毕后再返回吗?它如何知道何时加载?

非常感谢任何帮助!

【问题讨论】:

    标签: javascript reactjs redux redux-saga next.js


    【解决方案1】:
      1234563您的应用程序,但是在您的 compose HoC 中,您必须再次实现 getInitialProps,然后执行最终 page.js 的 getInitialProps)。每个页面都可以有一个自己的 getInitialProps(例如,在您的联系页面上,您想要加载您的公司地址,并且仅在您的整个应用程序中)。 _app.js 执行 Component.getInitProps(如果设置)。如果组件的方法返回一个非空对象,它将成为您的 pageProps,您最终在 render 方法中提供给组件。 1234563并返回一个布尔值。商店水合后,您的组件将被更新,因为您在商店中的道具已加载/更新。

    但是我现在面临同样的问题:

    我在我的 getInitProps 中调度 saga 任务,但由于操作是异步的,我在 ComponentDidMount 之后收到了道具。

    编辑:

    Link to read

    TL:DR;

    • Saga 任务是线程,或者如果您想要一种事件侦听器。
    • 每次您调度一个 saga 动作(取决于您的 saga)时,都会启动一个侦听器
    • 在我们的例子中,如果我们在 getInitialProps 中触发一个动作,我们会使用 saga 任务将动作分派到商店,但是 store.dispatch 方法不是 async => 导致 getInitialProps 不会被动作阻止并立即返回道具,尽管已触发的任务未完成
    • Victor 的解决方案以及 next-redux-saga 包中的解决方案是 1. 调度停止当前根任务的 'END' 操作和 2. 应用 toPromise() 方法,使您能够异步等待让传奇结束。 => 你有点阻止 getInitialProps 并强制方法在方法返回之前等待 sagas 结束;
    • 重要提示:当您停止 saga 线程时,这没问题,并且必须/应该在服务器上完成,但您的应用程序需要客户端的 sagas 才能正确处理存储副作用,因此如果 !isServer,您必须重新运行 sagas。

    更新:

    它不起作用。您只能停止服务器上的 sagas,因为您只需要它们进行初始执行,之后服务器上的 sagas 就没什么用了。但是在客户端,您无法停止 sagas。

    这是我的 store.js... 您可以执行初始 sagas,服务器将在 getInitialProps 中等待它们完成,因为 toPromise() 使停止异步。

    在客户端,您必须按照自己的方式完成生命周期等......客户端商店水合作用无法像我预期的那样工作。也许这会更好,否则你会阻止 React 渲染,这通常与 React 背道而驰。

      store.runSagas = () => {
        if (!store.currentSagas) {
          store.currentSagas = sagaMiddleware.run(rootSaga);
        }
      };
    
      store.stopSagas = async () => {
        if (store.currentSagas) {
          store.dispatch(END);
          await store.currentSagas.toPromise();
        }
      };
    
      store.execTasks = isServer => async (tasks = []) => {
        tasks.forEach(store.dispatch);
        if (isServer) {
          await store.stopSagas();
        }
      };
    

    【讨论】: