Используя Next JS для выполнения SSR с компонентами класса и getInitialProps, метод render содержит неопределенные данные - PullRequest
0 голосов
/ 20 февраля 2020

Я довольно новичок в JavaScript / React / Next JS. Я написал приложение React и сейчас пытаюсь преобразовать его так, чтобы оно отображалось на сервере.

Я прошел учебные курсы по https://nextjs.org/learn/basics/getting-started, а затем попытался применить эти знания к моему приложению.

У меня есть следующие требования в моем приложении

  • У меня есть сценарий основной детали. Главная страница отображает список статей, нажав на одну из этих статей, пользователь попадает в подробности статей.
  • Я хочу иметь чистые URL, такие как "/ article / 123", а не "article? Id = 123".
  • Я использую стороннюю библиотеку для получения данных из сервер, поэтому я должен использовать обещания для получения данных
  • Мне нужно использовать компоненты класса, а не функциональные компоненты (по другим причинам не могут перейти к функциональным компонентам).
  • Я хочу, чтобы весь рендеринг происходил на сервере, а не на клиенте

Мне неясно, как в "getInitialProps" я бы вызвал свой метод asyn c в моей сторонней библиотеке и вернуть данные. Ничего, что я пробую, не работает, и поиск в Google не помог.

Моя структура проекта

- components
     |- header.js
     |- footer.js
     |- layout.js
- pages
     |- index.js
     |- article
          |- [id].js
- scripts
     |- utils.js

index. js просто отображает 2 ссылки для 2 статей

export default function Index() {
     return (
        <div>
            <Link href="/article/[id]" as={`/article/1`}>
                <a>Article 1</a>
            </Link>
            <Link href="/article/[id]" as={`/article/2`}>
                <a>Article 2</a>
            </Link>
        </div>
    );
} 

utils. js имеет метод util для вызова метода сторонней библиотеки

export function getDataFromThirdPartyLib(articleId) { 
    return thirdPartyLib.getMyData({
        "articleId" : articleId,
    }).then(function (item) {  
        return item;
   });
 }

article / [id]. js имеет

 function getData(articleId){
     console.log("getData")
     getDataFromThirdPartyLib(articleId)
        .then((item) => {
            console.log("got data")
            return {
                item: item
            }
        });
 } 

 class ArticleDetails extends React.Component {

     static async getInitialProps(ctx) {
         const data = await getData(articleId);
         // I also tried the following
         // const data = getData(articleId);

         return{
             data : data 
         }
     }

     render() {
         console.log("IN RENDER")
         console.log("this.props.data") // THIS IS UNDEFINED
         // my HTML
     }
  }

Проблема :

ведение журнала консоли показывает, что данные всегда неопределены в render (). Я вижу, как мои данные регистрируются при получении данных, и данные получаются, но они отображаются после моего ведения журнала рендеринга, поэтому рендеринг не обновляется после получения данных.

Другая попытка 1

Я пытался использовать «getData» внутри определения моего компонента (в отличие от внешнего), но это всегда не удавалось, так как «getData» не является функцией.

 class ArticleDetails extends React.Component {

     static async getInitialProps(ctx) {
         const data = await getData(articleId); // FAILS AS SAYS getData is not a function

         return{
             data : data 
         }
     }

     getData(articleId){
         console.log("getData")
         getDataFromThirdPartyLib(articleId)
            .then((item) => {
                return {
                    item: item
                }
            });
     } 

     render() {
         console.log("IN RENDER")
         console.log(this.props.data) // THIS IS UNDEFINED
         // my HTML
     }
  }

Другой попытка 2

Я пытался получить логи c в "getData" непосредственно в "getInitialProps", но это также не работает, так как говорит, что getInitialProps должен вернуть объект.

 class ArticleDetails extends React.Component {

     static async getInitialProps(ctx) {
          getDataFromThirdPartyLib(articleId)
            .then((item) => {
                return {
                    data: data
                }
          });
     }

     render() {
         console.log("IN RENDER")
         console.log(this.props.data) // THIS IS UNDEFINED
         // my HTML
     }
  }

Рабочая версия - но не SSR

Единственный способ заставить это работать - написать его как компонент класса в приложении React. Но я считаю, что "componentDidMount" не вызывается на сервере, а вызывается в клиенте. Так что это побеждает мою попытку получить все для рендеринга на сервере.

class ArticleDetails  extends React.Component {

    state = {
        item: null,


    componentDidMount() {
        this.getData();
    }


    getData(articleId){
         console.log("getData")
         getDataFromThirdPartyLib(articleId)
            .then((item) => {
                self.setState({                
                    item: item
                }
            });
    } 

    render() {
         console.log("IN RENDER")
         console.log(this.state.item) // THIS HAS A VALUE
         // my HTML
    }    

}

SOLUTION, предоставленное Стивом Холгадо

Проблема заключалась в том, что мой метод "getData" не возвращал обещание, как сказал Стив.

Однако мой метод "getData" был немного более сложным, чем я изначально писал в этом посте, поэтому, когда я впервые попробовал решение Стива, он не работал.

В мои getData вложены два обещания. Если я поставлю возврат на ОБЕ обещания, это работает отлично.

function getData(articleId){
     return getDataFromThirdPartyLib(articleId)
        .then((item) => {

             return getSecondBitOfDataFromThirdPartyLib(item)
                .then((extraInfo) => {
                    return {
                        item: item,
                        extraInfo : extraInfo
                    }
                });

            return {
                item: item
            }
        });
}  

1 Ответ

1 голос
/ 20 февраля 2020

Вам необходимо вернуть обещание от getData в article/[id].js:

function getData(articleId){
  // return promise here
  return getDataFromThirdPartyLib(articleId)
    .then((item) => {
      return {
        item: item
      }
    });
}

... в противном случае undefined возвращается неявно.

Кроме того, куда вы получаете articleId из?

Это должно быть из URL?

static async getInitialProps(ctx) {
  const articleId = ctx.query.id;
  const data = await getData(articleId);

  return {
    data: data 
  }
}

Надеюсь, это поможет.

...