likes
comments
collection
share

Nextjs 构建应用基础:数据获取一、数据获取和缓存 1.服务端 fetchAPI获取数据: 使用上面的方式获取数据数

作者站长头像
站长
· 阅读数 53

一、数据获取和缓存

1.服务端

  • fetchAPI获取数据:

    export default async function Page() {
      let data = await fetch('https://api.vercel.app/blog')
      let posts = await data.json()
      return (
        <ul>
          {posts.map((post) => (
            <li key={post.id}>{post.title}</li>
          ))}
        </ul>
      )
    }
    

    使用上面的方式获取数据数据将被缓存,关闭缓存的方式如下:

      let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' })
    

    在同一个page中多次使用fetch请求相同路径,其结果会被记录

  • 使用ORM等方式获取:

    import { db, posts } from '@/lib/db'
    
    export default async function Page() {
      let allPosts = await db.select().from(posts)
      return (
        <ul>
          {allPosts.map((post) => (
            <li key={post.id}>{post.title}</li>
          ))}
        </ul>
      )
    }
    

    使用上面的方式获取数据数据将被缓存,关闭缓存的方式如下:

    export const dynamic = 'force-dynamic'
    

当路由中不存在动态函数时,上述两种请求方式获得的数据会在项目构建时进行预渲染。然后通过增量静态生成的方式来更新数据。

2.客户端

  • 类似服务端可使用fetchAPI请求数据
    'use client'

    import { useState, useEffect } from 'react'

    export function Posts() {
      const [posts, setPosts] = useState(null)

      useEffect(() => {
        async function fetchPosts() {
          let res = await fetch('https://api.vercel.app/blog')
          let data = await res.json()
          setPosts(data)
        }
        fetchPosts()
      }, [])

      if (!posts) return <div>Loading...</div>

      return (
        <ul>
          {posts.map((post) => (
            <li key={post.id}>{post.title}</li>
          ))}
        </ul>
      )
    }
  • 使用ORM和数据库获取: 可以通过使用unstable_cacheAPI去缓存响应,允许页面在构建时进行预渲染,同时设置了缓存时间以及标签,可以通过增量静态生成使其失效。
import { unstable_cache } from 'next/cache'
import { db, posts } from '@/lib/db'
 
const getPosts = unstable_cache(
  async () => {
    return await db.select().from(posts)
  },
  ['posts'],
  { revalidate: 3600, tags: ['posts'] }
)
 
export default async function Page() {
  const allPosts = await getPosts()
 
  return (
    <ul>
      {allPosts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

二、数据获取模式: 并行和顺序

Nextjs 构建应用基础:数据获取一、数据获取和缓存 1.服务端 fetchAPI获取数据: 使用上面的方式获取数据数

1.顺序获取:

如下,由于Playlists组件依赖于artistID参数,Playlists组件只有在Artist组件请求结束之后再开始请求数据此时可以使用loadng.js路由或者Suspense组件包裹处理。

export default async function Page({
  params: { username },
}: {
  params: { username: string }
}) {
  // Get artist information
  const artist = await getArtist(username)
 
  return (
    <>
      <h1>{artist.name}</h1>
      {/* Show fallback UI while the Playlists component is loading */}
      <Suspense fallback={<div>Loading...</div>}>
        {/* Pass the artist ID to the Playlists component */}
        <Playlists artistID={artist.id} />
      </Suspense>
    </>
  )
}
 
async function Playlists({ artistID }: { artistID: string }) {
  // Use the artist ID to fetch playlists
  const playlists = await getArtistPlaylists(artistID)
 
  return (
    <ul>
      {playlists.map((playlist) => (
        <li key={playlist.id}>{playlist.name}</li>
      ))}
    </ul>
  )
}

2.并行获取:

通过在组件外部发起请求,避免async/await对请求的阻塞;

import Albums from './albums'
 
async function getArtist(username: string) {
  const res = await fetch(`https://api.example.com/artist/${username}`)
  return res.json()
}
 
async function getAlbums(username: string) {
  const res = await fetch(`https://api.example.com/artist/${username}/albums`)
  return res.json()
}
 
export default async function Page({
  params: { username },
}: {
  params: { username: string }
}) {
  const artistData = getArtist(username)
  const albumsData = getAlbums(username)
 
  // Initiate both requests in parallel
  const [artist, albums] = await Promise.all([artistData, albumsData])
 
  return (
    <>
      <h1>{artist.name}</h1>
      <Albums list={albums} />
    </>
  )
}

三、数据预加载

可以通过创建一个函数,在阻塞请求之前立即调用该函数。 如下:checkIsAvailable() 会阻止 <Item/> 渲染,因此可以在它之前调用 preload() 获取<Item/> 组件依赖数据。在渲染<Item/>时,其数据已被提取。

import { getItem } from '@/utils/get-item'
 
export const preload = (id: string) => {
  // void evaluates the given expression and returns undefined
  // https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/void
  void getItem(id)
}
export default async function Item({ id }: { id: string }) {
  const result = await getItem(id)
  // ...
}
import Item, { preload, checkIsAvailable } from '@/components/Item'
 
export default async function Page({
  params: { id },
}: {
  params: { id: string }
}) {
  // starting loading item data
  preload(id)
  // perform another asynchronous task
  const isAvailable = await checkIsAvailable()
 
  return isAvailable ? <Item id={id} /> : null
}

二、 Server Actions

Server Actions: 在服务端执行的异步函数,可以在服务端和客户端组件中使用,以处理 Next.js 应用中的表单数据提交和更改。 通过在页面中添加标记"use server":

  1. 添加在异步函数顶部:将函数作为Server Action;
  2. 添加在页面顶部: 将页面导出的函数都变为Server Action;

通过使用Server Action简化了以往需要处理HTTP进行客户端和服务端的交互过程(nextjs.org/docs/app/bu…)

export default function Page() {
  async function createInvoice(formData: FormData) {
    'use server'
 
    const rawFormData = {
      customerId: formData.get('customerId'),
      amount: formData.get('amount'),
      status: formData.get('status'),
    }
 
    // mutate data
    // revalidate cache
  }
 
  return <form action={createInvoice}>...</form>
}

具体使用实例参照文档


总结:

  1. 服务端数据获取与缓存:使用 fetch API 或 ORM 在服务端获取数据,支持数据缓存和预渲染,可通过设置禁用缓存。
  2. 客户端数据获取:客户端同样可以使用 fetch API 或 unstable_cache API 进行数据获取,并支持数据缓存。
  3. 数据获取模式:支持顺序获取和并行获取数据,以适应不同的组件数据依赖关系。
  4. 数据预加载:通过预加载函数提前获取数据,减少组件渲染时的数据获取延迟。
  5. Server Actions:在服务器端执行的异步函数,用于处理表单提交和数据变更,简化了客户端与服务器的交互过程。
转载自:https://juejin.cn/post/7415662205616619571
评论
请登录