Я довольно новичок в 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
}
});
}