NextJS официальный пример кода: _app.getInitialProps вызывает Component.getInitialProps - это чтобы убедиться, что все страницы загружают данные? - PullRequest
0 голосов
/ 25 января 2019

Я пытаюсь понять, как подключить 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' />
  }
}

Будет ли this getInitialProps ждать возврата, пока все данные не будут загружены?Как он узнает, когда загрузится?

Любая помощь очень ценится!

1 Ответ

0 голосов
/ 03 июня 2019
  1. Поскольку _app.js - это HoC, ваш Компонент внутри _app.js - это, по сути, страница, которую вы хотите загрузить из папки страниц (если вы создаете дальше, вы можете распространять другой HoC и впоследствии загружать свою страницу, зависит от ваше приложение, но затем в вашем сочинительном HoC вы должны снова реализовать getInitialProps и затем выполнить getInitialProps вашего последнего page.js). Каждая страница может иметь свой собственный getInitialProps (например, на странице контактов вы хотите загрузить адрес своей компании и только там во всем приложении). _app.js выполняет Component.getInitProps (если установлено). Если метод Компонента возвращает непустой объект, он становится вашим PageProps, который вы, наконец, предоставляете Компоненту внутри метода рендеринга.

  2. В вашем page.js теперь реализован метод getInitProps, который отправляет саг-задачу и возвращает isServer ... при условии, что только ваше хранилище гидратируется отправкой действия - getInitProps не нужно ничего ждать и возвращает логическое значение. После увлажнения магазина ваш компонент будет обновлен, так как ваши реквизиты в магазине загружены / обновлены.

Однако сейчас я сталкиваюсь с той же проблемой:

Я отправляю саги Задачи в моем getInitProps, но поскольку действия асинхронные, я получаю реквизиты после ComponentDidMount.

EDIT:

Ссылка для чтения

TL: DR;

  • Задачи Saga - это потоки или, если вы хотите что-то вроде слушателей событий.
  • Каждый раз, когда вы отправляете действие саги (в зависимости от вашей саги), слушатель раскручивается
  • В нашем случае, если мы запускаем действие в нашем getInitialProps, мы отправляем действия в хранилище с помощью саг-задач, однако метод store.dispatch не async =>, что приводит к тому, что getInitialProps не блокируется действием и мгновенно возвращает реквизиты, хотя запущенные задания не завершены
  • Решение Виктора, а также решение из пакета next-redux-saga: 1. отправить действие 'END', которое останавливает текущую корневую задачу, и 2. применить метод toPromise (), который дает вам возможность асинхронно ждать для саг до конца. => Вы как бы блокируете getInitialProps и заставляете метод ждать завершения саг до возврата метода;
  • Важно: когда вы останавливаете свои потоки саги, это нормально, и ДОЛЖНО / ДОЛЖНО быть выполнено на сервере, но вашему приложению нужны саги на стороне клиента для правильной обработки побочных эффектов магазина, таким образом, вы ДОЛЖНЫ перезапускать саги, если! IsServer.

UPDATE:

Это не работает. Вы можете остановить саги на сервере только потому, что они нужны только для первоначального выполнения, саги на сервере впоследствии бесполезны. Однако на стороне клиента вы не можете остановить саги.

Вот мой store.js ... вы можете выполнить начальные саги, и сервер будет ждать их завершения в 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();
    }
  };
...