由于我想将SSR添加到我即将进行的项目中以改善SEO,因此我想接下来尝试一下。我想要的是仅对初始页面使用SSR,而网站中的其余导航将是客户端渲染。在这种情况下,我认为getInitialProps最合适,因此相应地提供了文档。
据我了解,getInitialProps在服务器中运行以进行初始页面呈现,并在使用next / link导航时在浏览器中运行。我发现的问题是getInitialProps似乎阻止了页面呈现。 (即在getInitialProps完成后更改/呈现的页面)
import axios from 'axios'
function Posts(props) {
return (
<div>
<div>Posts:</div>
<div>
{JSON.stringify(props)}
</div>
</div>
)
}
Posts.getInitialProps = async (context) => {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
// Wait longer to see the effect
// await (new Promise((resolve) => {
// setTimeout(resolve, 5000)
// }))
return {
props: {
posts: response.data
}
}
}
export default Posts;
我该如何像在纯React中那样,首先渲染jsx,然后填写道具?(首先会忽略执行JSON.stringify(props))
此外,在接下来的9.3版中,该团队引入了getServerSideProps,建议在getInitialProps上使用。当它们与服务器上运行的getServerSideProps不同时,如何比较?
答案 0 :(得分:3)
根据您的评论,您希望在初始页面加载时在服务器上进行提取。但是,如果在页面之间导航,则您不希望在等待getInitialProps
返回时阻止渲染。
一种解决方案是检查您是否在服务器上,然后在getInitialProps
中进行提取。如果在客户端上,请不要在getInitialProps
中进行提取,而应在渲染方法中使用useEffect
进行提取。
import {useEffect} from 'react'
import axios from 'axios'
const isServer = () => typeof window === 'undefined'
const getPosts = () => {
return axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => response.data)
}
function Posts({posts}) {
const [renderPosts, setRenderPosts] = useState(posts)
useEffect(() => {
if(posts === null) {
getPosts()
.then(setRenderPosts)
}
}, [])
return (
<div>
<div>Posts:</div>
<div>
{JSON.stringify(renderPosts)}
</div>
</div>
)
}
Posts.getInitialProps = async (context) => {
if(isServer()) {
return {
posts: await getPosts(),
}
}
else {
return {
posts: null,
}
}
}
export default Posts
顺便说一句,您可能会在这里使用getServerSideProps
,因为只有在服务器上渲染时才会调用它。但是,呈现使用getServerSideProps
的页面时,即使您正在使用getServerSideProps
进行导航,它实际上也会调用服务器以从next/link
获取数据。来自Next.js 9.3 blog post:
当使用next / link在页面之间导航而不是在浏览器中执行getServerSideProps时,Next.js将对服务器进行提取,这将返回调用getServerSideProps的结果。
这仍然会导致您要避免的阻止问题。
最后一点,这可能不是惯用的解决方案。可能会有更“标准”的解决方案。我只是找不到一个。您可能还可以在页面组件周围使用包装器,以更一致的方式完成所有这些操作。如果您经常使用这种模式,建议您这样做。