全栈开发个人博客08.前端接入Graphql

@apollo/client 是一个用于与 GraphQL 后端进行交互的库,提供了简洁的 API 和强大的功能,帮助开发者在 React 等前端框架中轻松实现数据查询、缓存管理和状态管理。

1. layout使用 @apollo/client provider

tsx 复制代码
//[locale]/layout.tsx

import { ApolloWrapper } from '@/lib/ApolloProvider'

//... ohter code

export default async function LocaleLayout({ children, params }: Props) {
  return (
    <html lang={locale} suppressHydrationWarning>
      <body>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
          disableTransitionOnChange
        >
          <NextIntlClientProvider>
            <ApolloWrapper>{children}</ApolloWrapper>
            <Toaster />
          </NextIntlClientProvider>
        </ThemeProvider>
      </body>
    </html>
  )
}

2. 定义 ApolloWrapper 组件

tsx 复制代码
'use client'

import type React from 'react'

import {
  ApolloClient,
  ApolloProvider,
  InMemoryCache,
  HttpLink,
} from '@apollo/client'
import { useMemo } from 'react'

// Function to create a new Apollo Client instance
function createApolloClient() {
  return new ApolloClient({
    cache: new InMemoryCache({}),
    link: new HttpLink({
      uri: '/api/graphql',
      // You can add additional options here like headers, credentials, etc.
    }),
    defaultOptions: {
      watchQuery: {
        fetchPolicy: 'cache-and-network',
      },
    },
  })
}

// Provider component that wraps your app and makes Apollo Client available
export function ApolloWrapper({ children }: { children: React.ReactNode }) {
  const client = useMemo(() => createApolloClient(), [])

  return <ApolloProvider client={client}>{children}</ApolloProvider>
}

3. 查询单个文章

在客户端组件中可以使用 useQuery 获取数据, 或者 useApolloClient() 来获取 apolloClient,再用 apolloClient.query() 来查询数据

tsx 复制代码
import { gql, useMutation, useQuery } from '@apollo/client'
//...
const GET_POST = gql`
  query GetPost($id: ID!) {
    post(id: $id) {
      id
      title
      summary
      content
    }
  }
`
const id = searchParams.get('id')
const {
  data: postDsata1,
  loading,
  error,
} = useQuery(GET_POST, {
  variables: {
    id,
  },
})

const { data: postData2 } = await apolloClient.query({
  query: GET_POST,
  variables: {
    id,
  },
})

4. 在服务端组件使用 apolloClient

定义服务端 apolloClient 实例

tsx 复制代码
// lib/apolloServerClient.ts
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client'

export function getApolloServerClient() {
  const httpLink = new HttpLink({
    uri: process.env.GRAPHQL_ENDPOINT || 'http://localhost:3000/api/graphql',
  })

  return new ApolloClient({
    cache: new InMemoryCache(),
    link: httpLink,
    // Important for SSR to avoid leaking data between requests
    ssrMode: true,
  })
}

在服务端组件中使用,例如文章详情 page.tsx

Next.js构建时会优先静态渲染,这里我们强制设置使用动态渲染 export const dynamic = 'force-dynamic',每次都拿最新的数据 export const revalidate = 0

tsx 复制代码
import { getApolloServerClient } from '@/lib/apolloServerClient'
import { gql } from '@apollo/client'
import { format } from 'date-fns'
import { Locale } from 'next-intl'
import { setRequestLocale } from 'next-intl/server'

export const dynamic = 'force-dynamic'
export const revalidate = 0

type Props = {
  params: Promise<{ locale: Locale; id: string }>
}

export default async function PagePostsDetail({ params }: Props) {
  const { locale, id } = await params
  setRequestLocale(locale)


  const { data } = await getApolloServerClient().query({
    query: gql`
      query GetPost($id: ID!, $userId: ID) {
        post(id: $id) {
          id
          title
          summary
          content
          createdAt
          updatedAt
          createdBy {
            id
            nickname
          }
        }
      }
    `,
    variables: {
      id,
    },
  })

  return (
    <div className="page-wrapper py-6">
      <div className="">
        <div key={data.post.id} className="relative flex flex-col gap-4">
          <div className="text-xl font-bold">{data.post.title}</div>
          <div className="text-muted-foreground flex items-center gap-2 text-sm">
            <span>{data.post.createdBy.nickname}</span>
            <span>{format(data.post.createdAt, 'yyyy.MM.dd HH:mm')}</span>
          </div>

      </div>
    </div>
  )
}
相关推荐
To_OC5 小时前
写了三天 Next.js,我的 React 世界观被拆了又装回去
前端·全栈·next.js
JieE21213 小时前
Next.js App Router 全栈实战:从零构建一个 Markdown 笔记系统
全栈·next.js
濮水大叔2 天前
CabloyJS 强大之处不仅仅是 IoC,而是全栈资源的寻址体系
typescript·node.js·全栈
东方小月2 天前
从零开发一个 Coding Agent(十一):实现 CLI 的 print 模式
node.js·全栈
浮生望2 天前
Next.js App Router 实战入门:从 SPA 到 SSR 的全栈思维转变
全栈
用户938515635073 天前
Next.js 笔记系统(二):Redis 数据服务与侧边栏组件拆分实战
javascript·全栈
用户938515635073 天前
从 0 拆解一个 Next.js 笔记系统:npx、App Router、RSC 与组件规划全记录
前端·后端·全栈
GitLqr3 天前
玩转 Flutter 中的 Stack 与 Positioned:解决 UI 重叠问题的实战指南
flutter·面试·全栈
To_OC4 天前
后端接口还没交付,前端如何独立把整套业务跑通
前端·react.js·全栈
用户852495071844 天前
Next.js 入门实战:从 SPA 到全栈,一次搞懂
全栈