使用 NextJS 对 Class 组件和 getInitialProps 进行 SSR,render 方法有未定义的数据
Using NextJS to do SSR with Class Components and getInitialProps, render method has undefined data
我是 JavaScript/React/NextJS 的新手。我已经编写了一个 React 应用程序,现在我正在尝试对其进行转换,以便所有内容都呈现在服务器上。
我学习了 https://nextjs.org/learn/basics/getting-started 上的教程,然后尝试将这些知识应用到我的应用程序中。
我的应用程序有以下要求
- 我有一个主要细节场景。主页呈现文章列表,单击其中一篇文章会将用户带到文章详细信息。
- 我想要干净的 url,例如“/article/123”而不是 "article?id=123"。
- 我正在使用第 3 方库从服务器获取数据,因此我必须使用 promises 来获取数据
- 我需要使用Class组件而不是功能组件(由于其他原因无法移动到功能组件)。
- 我希望所有渲染都发生在服务器而不是客户端
我不清楚如何在 "getInitialProps" 中调用我的第 3 方库中的异步方法和 return 数据。我尝试的任何方法都不起作用,谷歌搜索也无济于事。
我的项目结构是
- 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;
});
}
文章/[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
我尝试直接在 "getInitialProps" 中使用 "getData" 中的逻辑,但这也不起作用,因为它说 getInitialProps 必须 return 一个对象。
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 应用程序中的 class 组件一样编写它。但我相信 "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
}
}
Steve Holgado 提供的解决方案
问题是我的 "getData" 方法没有 return 像史蒂夫所说的那样承诺。
然而,我的 "getData" 方法比我最初在这个 post 中输入的要复杂一些,这就是为什么当我第一次尝试 Steve 的解决方案时它不起作用的原因。
我的 getData 嵌套了两个承诺。如果我将 return 放在 BOTH promises 上,它会完美运行。
function getData(articleId){
return getDataFromThirdPartyLib(articleId)
.then((item) => {
return getSecondBitOfDataFromThirdPartyLib(item)
.then((extraInfo) => {
return {
item: item,
extraInfo : extraInfo
}
});
return {
item: item
}
});
}
您需要 return getData
在 article/[id].js
中的承诺:
function getData(articleId){
// return promise here
return getDataFromThirdPartyLib(articleId)
.then((item) => {
return {
item: item
}
});
}
...否则 undefined
被隐式 returned。
另外,你从哪里得到 articleId
?
它应该来自 url 吗?
static async getInitialProps(ctx) {
const articleId = ctx.query.id;
const data = await getData(articleId);
return {
data: data
}
}
希望这对您有所帮助。
我是 JavaScript/React/NextJS 的新手。我已经编写了一个 React 应用程序,现在我正在尝试对其进行转换,以便所有内容都呈现在服务器上。
我学习了 https://nextjs.org/learn/basics/getting-started 上的教程,然后尝试将这些知识应用到我的应用程序中。
我的应用程序有以下要求
- 我有一个主要细节场景。主页呈现文章列表,单击其中一篇文章会将用户带到文章详细信息。
- 我想要干净的 url,例如“/article/123”而不是 "article?id=123"。
- 我正在使用第 3 方库从服务器获取数据,因此我必须使用 promises 来获取数据
- 我需要使用Class组件而不是功能组件(由于其他原因无法移动到功能组件)。
- 我希望所有渲染都发生在服务器而不是客户端
我不清楚如何在 "getInitialProps" 中调用我的第 3 方库中的异步方法和 return 数据。我尝试的任何方法都不起作用,谷歌搜索也无济于事。
我的项目结构是
- 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;
});
}
文章/[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
我尝试直接在 "getInitialProps" 中使用 "getData" 中的逻辑,但这也不起作用,因为它说 getInitialProps 必须 return 一个对象。
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 应用程序中的 class 组件一样编写它。但我相信 "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
}
}
Steve Holgado 提供的解决方案
问题是我的 "getData" 方法没有 return 像史蒂夫所说的那样承诺。
然而,我的 "getData" 方法比我最初在这个 post 中输入的要复杂一些,这就是为什么当我第一次尝试 Steve 的解决方案时它不起作用的原因。
我的 getData 嵌套了两个承诺。如果我将 return 放在 BOTH promises 上,它会完美运行。
function getData(articleId){
return getDataFromThirdPartyLib(articleId)
.then((item) => {
return getSecondBitOfDataFromThirdPartyLib(item)
.then((extraInfo) => {
return {
item: item,
extraInfo : extraInfo
}
});
return {
item: item
}
});
}
您需要 return getData
在 article/[id].js
中的承诺:
function getData(articleId){
// return promise here
return getDataFromThirdPartyLib(articleId)
.then((item) => {
return {
item: item
}
});
}
...否则 undefined
被隐式 returned。
另外,你从哪里得到 articleId
?
它应该来自 url 吗?
static async getInitialProps(ctx) {
const articleId = ctx.query.id;
const data = await getData(articleId);
return {
data: data
}
}
希望这对您有所帮助。