原始文檔在 https://github.com/developerw... 如今搬過來.git
學習 Next.js: 入門
學習 Next.js: 頁面之間的導航
學習 Next.js: 使用共享組件
學習 Next.js: 建立動態內容
學習 Next.js: 使用路由掩碼建立乾淨的URL
學習 Next.js: 乾淨URL的服務器支持
學習 Next.js: 獲取數據
學習 Next.js: 部署github
得益於 Next.js 路由API的優勢, 咱們知道了如何建立一個具備簡介URL的 Next.js 應用程序.shell
實際上, 咱們一般須要從遠程數據源獲取數據. Next.js 提供了一個標準API用於爲頁面獲取數據. 咱們使用一個 async
函數 getInitialProps
來達到獲取數據的目的.npm
以此爲基礎, 咱們可以給以頁面從遠程數據源獲取數據, 而後把數據穿給咱們的一個頁面組件的屬性. 咱們能夠編寫getInitialProps
函數讓他可以同時在客戶端和服務器端運行.json
在這節課中, 使用 getInitialProps
, 咱們將使用 TVmaze API構造一個顯示Batman TV Shows 相關信息的應用程序.segmentfault
如今開始!api
下載須要的示例程序:瀏覽器
git clone https://github.com/arunoda/learnnextjs-demo.git cd learnnextjs-demo git checkout clean-urls-ssr
用下面的命令運行:服務器
npm install npm run dv
而後, 訪問 http://localhost:3000app
在咱們的演示程序中, 顯示了一個博客列表, 如今咱們改造演示程序以要顯示一個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 文檔.