首页 > 解决方案 > NextJS 官方示例代码:_app.getInitialProps 调用 Component.getInitialProps——这是为了确保所有页面都加载数据吗?

问题描述

我试图了解如何将 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' />
  }
}

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

非常感谢任何帮助!

标签: javascriptreactjsreduxredux-saganext.js

解决方案


  1. 由于 _app.js 是一个 HoC,因此 _app.js 中的组件基本上就是您要从 pages 文件夹加载的页面(如果您进一步编写,您可以传播另一个 HoC,然后加载您的页面,这取决于您的应用程序,但随后在你的 compose HoC 你必须再次实现 getInitialProps 然后执行你最终 page.js 的 getInitialProps)。每个页面都可以有一个自己的 getInitialProps(例如,在您的联系页面上,您想要加载您的公司地址,并且仅在您的整个应用程序中)。_app.js 执行 Component.getInitProps(如果设置)。如果组件的方法返回一个非空对象,它将成为您的 pageProps,您最终在 render 方法中将其提供给组件。

  2. 您的 page.js 现在实现了一个 getInitProps 方法,该方法分派一个传奇任务并返回 isServer ...给定的情况下,只有您的商店通过分派操作来补充水分 - getInitProps 不必等待任何东西并返回一个布尔值。商店补水后,您的组件将被更新,因为您在商店中的道具已加载/更新。

但是我目前面临同样的问题:

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

编辑:

阅读链接

TL:博士;

  • Saga 任务是线程,或者如果您想要一种事件侦听器。
  • 每次您发送一个 saga 动作(取决于您的 saga)时,都会启动一个侦听器
  • 在我们的例子中,如果我们在 getInitialProps 中触发一个动作,我们会使用 saga 任务将动作分派到商店,但是 store.dispatch 方法不是 async => 导致 getInitialProps 不会被动作阻塞并立即返回道具,尽管触发的任务还没有完成
  • Victor 的解决方案以及 next-redux-saga 包中的解决方案是 1. 调度停止当前根任务的 'END' 操作和 2. 应用 toPromise() 方法,它使您能够异步等待 sagas结束。=> 你有点阻止 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();
    }
  };

推荐阅读