现在我们知道如何创建一个像样的Next.js应用了,并且也充分使用了Next.js路由API。
在实践中,我们通常要从远程数据源获取数据。Next.js具备标准的获取数据的API,那就是成为同步函数的'getInitialProps'.用这个函数,我们就能从远程获取数据,并且以属性的方式传递回页面。我们能同时在客户端和服务端写入这个函数,所以,自然而然可以在两端使用。在这节课中,通过使用"getInitialProps",我们要建立一个能够展示“蝙蝠侠”电视节目信息的应用,并以公共的TVmaze API为数据源。让我们开始吧!
安装
在这节课中,我们仅仅需要一个简单的Next.js应用来掩饰。去下载如下事例应用:
git clone https://github.com/zeit/next-learn-demo.git
cd next-learn-demo
cd 6-fetching-data
用如下代码运行
npm install
npm run dev
然后就可以通过 http://localhost:3000/ 来访问这个应用了。
获取蝙蝠侠电视节目
在我们的事例应用中,首页有一个博客列表。现在我们要显示一个蝙蝠侠电视列表,对硬编码取而代之的是我们要从远程服务端获取数据。
在这里我们用TVMaze API(http://www.tvmaze.com/api)来获取电视节目。它是一个能够搜索电视节目信息的API
首先我们要安装'isomorphic-unfetch',这是一个可以获取数据的库,它是对浏览器的fetch API的简单实现,但却可以同时运行在客户端和服务端环境。
npm install --save isomorphic-unfetch
然后用如下内容来代替'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('https://api.tvmaze.com/search/shows?q=batman');
const data = await res.json();
console.log(`Show data fetched. Count: ${data.length}`);
return {
shows: data.map(entry => entry.show)
};
};
export default Index;
除了“Index.getInitialProps”以上的代码都对你是如此熟悉,正如下面所示
Index.getInitialProps = async function() {
const res = await fetch('https://api.tvmaze.com/search/shows?q=batman');
const data = await res.json();
console.log(`Show data fetched. Count: ${data.length}`);
return {
shows: data.map(entry => entry.show)
};
};
这是一个静态同步函数,你可以将它添加到你应用中的任何页面。使用它,我们就可以获取数据并且把数据作为属性传递到页面中了。
如你所见,我们拿到了蝙蝠侠电视节目列表并且将其以"shows"这个属性传递到页面中。
正如上面的"getInitialProps"这个函数,它在控制台打印出一些获取的数据,之后看看服务端控制台和浏览器的控制台,并且刷新页面。在刷新后你在哪里看到了数据的数量?
答案是:在服务端控制台
只在服务端
之所以只在服务端打印出了数据,是因为我们是在服务端渲染了页面,既然在服务端拿到了数据就没有理由再在客户端获取一遍。
实现Post页面
现在让我们去实现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);
});
然后重启你的项目,运行上面的代码
现在让我们替换"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(`https://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(`https://api.tvmaze.com/shows/${id}`);
const show = await res.json();
console.log(`Fetched show: ${show.name}`);
return { show };
};
在这个函数里的第一个参数是context对象,它有一个query字段用来获取获取数据。在我们的例子中,我们选择ID作为查询参数并且从TVMaze中获取数据。
在 " getInitialProps " 这个函数中,我们添加了"console.log"来打印标题。现在我们要看看打印在哪里显示。
同时打开服务端的控制台和客户端控制台。然后访问首页"http://localhost:3000" 并且店家第一个“蝙蝠侠节目”的标题。你会在哪里看到"console.log"的信息呢?
答案是:在浏览器控制台。
在客户端获取数据
我们看到在客户端显示了控制台信息,这是因为我们是依赖于客户端才导航到post页面的。当我们点击<Link>时,页面转换会发生在浏览器里,而不是向服务端请求。
如果你直接访问post页面(比如:http://localhost:3000/p/975),你就会发现信息是打印在服务端,而不是客户端!
最后
现在您已经知晓了使Next.js趋于完整的最重要的特性之一:获取数据和服务端渲染。通过学习"getInitialProps",我们足够可以应付大部分情况了。当然你也可以参考Next.js的文档来查询获取数据“data fetching”的更多信息!
【原文链接:https://nextjs.org/learn/basics/fetching-data-for-pages】