學習 Next.js: 獲取數據

原始文檔在 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

Batman TV Shows App

如今開始!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 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 屬性進行訪問.

Fetching data as component property

如你所見, 上面的 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 文檔.

相關文章
相關標籤/搜索