原始文档在 https://github.com/developerw... 现在搬过来.
学习 Next.js: 入门
学习 Next.js: 页面之间的导航
学习 Next.js: 使用共享组件
学习 Next.js: 创建动态内容
学习 Next.js: 使用路由掩码创建干净的URL
学习 Next.js: 干净URL的服务器支持
学习 Next.js: 获取数据
学习 Next.js: 部署
为页面获取数据
得益于 Next.js 路由API的优点, 我们知道了如何创建一个具有简介URL的 Next.js 应用程序.
实际上, 我们通常需要从远程数据源获取数据. Next.js 提供了一个标准API用于为页面获取数据. 我们使用一个 async
函数 getInitialProps
来达到获取数据的目的.
以此为基础, 我们能够给以页面从远程数据源获取数据, 然后把数据穿给我们的一个页面组件的属性. 我们可以编写getInitialProps
函数让他能够同时在客户端和服务器端运行.
在这节课中, 使用 getInitialProps
, 我们将使用 TVmaze API构造一个显示Batman TV Shows 相关信息的应用程序.
现在开始!
设置
下载需要的示例程序:
git clone https://github.com/arunoda/learnnextjs-demo.git
cd learnnextjs-demo
git checkout clean-urls-ssr
用下面的命令运行:
npm install
npm run dv
然后, 访问 http://localhost:3000
获取 Batman Shows
在我们的演示程序中, 显示了一个博客列表, 现在我们改造演示程序以要显示一个Batman TV shows列表.
和之前博客列表的硬编码方式不同, 这次我们从远程服务器获取列表数据
这里我们使用 TVMaze API 获取电视节目信息. 它是一个搜索电视节目信息的API.
首先, 我们需要按照 isomorphic-unfetch. 我们使用这个库来获取数据. 它是一个浏览器 fetch 的简单实现, 并且可以同时工作在客户端和服务器端环境中.
译注: 这类能够同时在客户端和服务器运行的应用程序, 我们称之为
同构应用程序
然后, 用下面的代码, 替换 pages/index.js
文件:
import Layout from '../components/MyLayout.js'
import Link from 'next/link'
import fetch from 'isomorphic-unfetch'
const Index = (props) => (
<Layout>
<h1>Batman TV Shows</h1>
<ul>
{props.shows.map(({show}) => (
<li key={show.id}>
<Link as={`/p/${show.id}`} href={`/post?id=${show.id}`}>
<a>{show.name}</a>
</Link>
</li>
))}
</ul>
</Layout>
)
Index.getInitialProps = async function() {
const res = await fetch('http://api.tvmaze.com/search/shows?q=batman')
const data = await res.json()
console.log(`Show data fetched. Count: ${data.length}`)
return {
shows: data
}
}
export default Index
到现在, 上面的代码一切看来都是很熟悉了, 除了 Index.getInitialProps
:
Index.getInitialProps = async function() {
const res = await fetch('http://api.tvmaze.com/search/shows?q=batman')
const data = await res.json()
console.log(`Show data fetched. Count: ${data.length}`)
return {
shows: data
}
}
这是一个静态的 async
, 可以把它添加到应用程序中的任何页面. 使用它, 我们可以获取数据, 并且作为页面组件的属性使用.
如你所见, 现在, 我们要获取 Batman TV 电视节目信息, 并且把获取的节目信息, 作为页面组件的 shows
属性进行访问.
如你所见, 上面的 getInitialProps
函数, 它打印一系列获取到的数据到控制台.
现在, 看一下浏览器的控制台和服务器的控制台输出. 然后重新加载页面.
仅服务器
本来我们预想的, 客户端和服务器都能输出同样的信息, 但实际上, 在这种情况下, 输出信息只显示在了服务器端的控制台上. 这是因为, 我们的页面是在服务器端进行渲染的. 我们在服务器上已经获取到了电视节目的数据, 没有理由在客户端再获取一次.
实现信息展示页面
现在我们要实现一个 /post
页面来展示电视节目的详细信息.
首先, 打开 server.js
文件, 用下面的代码修改路由 /p/:id
:
server.get('/p/:id', (req, res) => {
const actualPage = '/post'
const queryParams = { id: req.params.id }
app.render(req, res, actualPage, queryParams)
})
然后, 重启应用程序
先前, 我们映射了
title
查询参数到页面, 现在我们重命名为id
.
现在, 用下面的代码替换 pages/post.js
的内容:
import Layout from '../components/MyLayout.js'
import fetch from 'isomorphic-unfetch'
const Post = (props) => (
<Layout>
<h1>{props.show.name}</h1>
<p>{props.show.summary.replace(/<[/]?p>/g, '')}</p>
<img src={props.show.image.medium}/>
</Layout>
)
Post.getInitialProps = async function (context) {
const { id } = context.query
const res = await fetch(`http://api.tvmaze.com/shows/${id}`)
const show = await res.json()
console.log(`Fetched show: ${show.name}`)
return { show }
}
export default Post
我们再来看一下 getInitialProps
函数:
Post.getInitialProps = async function (context) {
const { id } = context.query
const res = await fetch(`http://api.tvmaze.com/shows/${id}`)
const show = await res.json()
console.log(`Fetched show: ${show.Title}`)
return { show }
}
现在这个函数的第一个参数为一个 context
对象, 其中包含了我们用于获取信息的查询字段.
在我们这个例子中, 我们从查询串中获取电视节目ID, 然后通过它来从 TVMaze API 获取数据.
在 getInitialProps
函数中, 我们添加了一个 console.log
调试输出来显示电视节目的标题. 下面我们来验证我们的程序是否能够正确运行.
打开服务器和客户端控制台, 访问 http://localhost:3000, 点击第一个电视节目标题.
输出显示在客户端还是服务器控制台?
从客户端获取数据
这里, 我们只在客户端的控制台上看到了调试输入. 这是因为我们是通过客户端进行导航的. 因此从客户端获取数据是更好的方式.
如果你直接访问Post页面(例如: http://localhost:3000/p/975), 你将会看到调试输出显示在了服务器端而非客户端.
最后
现在你学到了 Next.js 最为关键的特性: 通用数据获取
和服务器端渲染(SRR)
.
我们了解了 getInitialProps
, 在大多数情况下, 就足够了. 如果你要了解关于数据获取的更加深入的信息, 参考data fetching 文档.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。