Enables your React components to fetch data using Apollo GraphQL.
Note
You also get progressive rendering, fallback upon loading and/or error, and caching.
Installation
Basic usage
withFallback()
<head>
tags
How it works
See also
npm install @apollo/client @apollo/client-react-streaming graphql vike-react-apollo
- Extend
+config.js
:// pages/+config.js import vikeReact from 'vike-react/config' import vikeReactApollo from 'vike-react-apollo/config' export default { // ... extends: [vikeReact, vikeReactApollo] }
- Create
+ApolloClient.js
:// +ApolloClient.js import { ApolloClient, InMemoryCache } from '@apollo/client-react-streaming' export default (pageContext: PageContext) => new ApolloClient({ uri: 'https://countries.trevorblades.com', cache: new InMemoryCache() })
Note
The vike-react-apollo
extension requires vike-react
.
// Countries.jsx
import { useSuspenseQuery, gql } from '@apollo/client/index.js'
const Countries = () => {
const { data } = useSuspenseQuery(gql`
{
countries {
code
name
}
}
`)
return (
<ul>
{data.countries.map((country) => (
<li key={country.code}>{country.name}</li>
))}
</ul>
)
}
Note
Even though useSuspenseQuery()
is imported from @apollo/client
, you need to install vike-react-apollo
for it to work. (The useSuspenseQuery()
hook requires an HTML stream integration.)
withFallback(Component) // Use default loading fallback (see +Loading)
withFallback(Component, Loading) // Define loading fallback
withFallback(Component, Loading, Error) // Define loading and error fallback
withFallback(Component, undefined, Error) // Define error fallback
// Country.jsx
import { useSuspenseQuery, gql } from '@apollo/client/index.js'
import { withFallback } from 'vike-react-apollo'
const Country = withFallback(
({ code }) => {
const { data } = useSuspenseQuery(
gql`
query Country($code: String!) {
country(code: $code) {
name
}
}
`,
{
variables: {
code
}
}
)
return (
<div>
Name: <b>{data.country.name}</b>
</div>
)
},
({ code }) => <div>Loading country {code}</div>,
// The props `retry` and `error` are provided by vike-react-apollo
// Other props, such as `code`, are provied by the parent component
({ code, retry, error }) => (
<div>
Failed to load country {code}
<button onClick={() => retry()}>Retry</button>
</div>
)
)
+Loading
If you skip the Loading
parameter, then a default loading component (provided by vike-react
) is used. You can create a custom default loading component:
// pages/+Loading.jsx
export default { component: LoadingComponent }
function LoadingComponent() {
// Applies on a component-level
return <div>Loading...</div>
}
Instead of adding a loading fallback to the component, you can set a loading fallback to the page and layouts:
// pages/+Loading.jsx
export default { layout: LoadingLayout }
function LoadingLayout() {
// Applies to the page and all layouts
return <div>Loading...</div>
}
Note
The +Loading.layout
setting is optional and only relevant when using useSuspenseQuery()
without withFallback()
or withFallback(Component, false)
.
withFallback(Component, false) // Don't set any loading fallback
withFallback(Component, undefined) // Use default loading fallback
Manual <Suspense>
boundary
Technically speaking:
withFallback()
wraps the component inside a<Suspense>
boundary.+Loading.layout
adds a<Suspense>
boundary to the<Page>
component as well as to all<Layout>
components.
You can also manually add a <Suspense>
boundary at any arbitrary position:
import { Suspense } from 'react'
function SomePageSection() {
return (
<Suspense fallback={<div>Loading...</div>}>
<SomeDataFetchingComponent />
<SomeOtherDataFetchingComponent />
</Suspense>
)
}
To set tags such as <title>
and <meta name="description">
based on fetched data, you can use <Config>
, <Head>
, and useConfig()
.
import { useSuspenseQuery } from '@tanstack/react-query'
import { Config } from 'vike-react/Config'
import { Head } from 'vike-react/Head'
function Movies() {
const query = useSuspenseQuery(gql`
{
movies {
title
}
}
`)
const movies = query.data
return (
<Config title={`${movies.length} Star Wars Movies`} />
<Head>
<meta name="description" content={`All ${movies.length} movies from the Star Wars franchise.`} />
</Head>
<ul>{
movies.map(({ title }) => (
<li>{title}</li>
))
}</ul>
)
}
Upon SSR, the component is rendered to HTML and its data loaded on the server-side. On the client side, the component is merely hydrated.
Upon page navigation (and rendering the first page if SSR is disabled), the component is rendered and its data loaded on the client-side.
Note
With vike-react-apollo
you fetch data on a component-level instead of using Vike's data()
hook which fetches data on a page-level.
Note
Behind the scenes vike-react-apollo
integrates Apollo GraphQL into the HTML stream.