Nextjs 预数据获取| 青训营笔记

286 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 9 天。我们 Bocchi 小组采用 Nextjs 开发这次掘金站点的前端,这几天我们尝试与后端对接,这篇文章就来简要记录下实现过程(具体代码看下方仓库)。

仓库地址: github.com/Bocchi-Deve…

思路

预数据获取是 Nextjs 开发很重要的一环,我们可以采用 getInitialProps来进行数据获取,同时考虑到前端程序的健壮性,如果后端服务出现异常,我们前端也应该展示出无数据异常页面,而不是直接坏掉。

实现

为了能够正确获取预数据,我们可以在 _app.tsx 中写出如下代码:

App.getInitialProps = async (props: AppContext) => {
  const ctx = props.ctx

  const data = await AggregateApi.aggregateInfoRequest() // 获取预数据
  const appProps = await (async () => {
    try {
      return await NextApp.getInitialProps(props)
    } catch (e) {
      if (!data?.user) {
        throw e
      }
      
      if (ctx.res) {
        ctx.res.statusCode = 466
        ctx.res.statusMessage = 'No Data'
      }
      return null
    }
  })()

  return {
    ...appProps,
    initData: data,
  }
}

我们应该在 App 组件中进行判断,看是否成功获取到数据,如没有获取到就展示 <NoDataErrorView /> 组件。同时我们也应该把数据注入到对应的 Provider中,方便后续获取。另外这里的 <Wrapper/>组件主要用来布局页面,以及 SEO 相关的功能,这里就不过多叙述了。 具体实现如下:

const App: FC<AppProps & Record<'initData', IAggregate>> = ({
  Component,
  pageProps,
  initData,
}) => {
  const Inner = useMemo(() => {
    return initData.user ? (
      <Wrapper>
        <Component {...pageProps} />
      </Wrapper>
    ) : (
      <NoDataErrorView />
    )
  }, [Component, initData, pageProps])
  return (
    <RootStoreProvider>
      <InitialContextProvider value={initData}>{Inner}</InitialContextProvider>
    </RootStoreProvider>
  )
}
import type { FC, PropsWithChildren } from 'react'
import { createContext, memo, useMemo } from 'react'

import type { IAggregate } from '~/types/api/aggregate'

export const InitialContext = createContext({} as IAggregate)

export const InitialContextProvider: FC<
  PropsWithChildren<{ value: IAggregate }>
> = memo((props) => {
  return (
    <InitialContext.Provider
      value={useMemo(() => ({ ...props.value }), [props.value])}
    >
      {props.children}
    </InitialContext.Provider>
  )
})

无数据页实现如下:

import type { FC } from 'react'

import { API_URL } from '~/constants/env'

import { ErrorView } from '.'

export const NoDataErrorView: FC = () => {
  return (
    <ErrorView
      noSeo
      statusCode={'无数据'}
      showBackButton={false}
      description={
        <>
          <p>出现这个错误表示未获取到初始数据</p>
          <p>可能是 API 接口地址配置不正确,或者后端服务出现异常</p>
          <p>API 地址:{API_URL}</p>
        </>
      }
    />
  )
}

image.png

参考