Skip to content

Instantly share code, notes, and snippets.

@good-idea
Last active October 5, 2021 20:04
Show Gist options
  • Save good-idea/6a4963c38f857995d4da49c44eb400d0 to your computer and use it in GitHub Desktop.
Save good-idea/6a4963c38f857995d4da49c44eb400d0 to your computer and use it in GitHub Desktop.
SK Refetch hook
// all the existing imports..
import { useRefetch } from '../src/hooks'
const productQuery = gql`
...
`
interface Response {
allShopifyProduct: ShopifyProduct[]
}
interface ProductPageProps {
product: ShopifyProduct
preview?: boolean // 👈 new
}
const getProductFromResponse = (response: Response) => {
const products = response?.allShopifyProduct
const product = products && products.length ? products[0] : null
return product
}
const Product = ({ product, preview }: ProductPageProps) => {
const data = useRefetch<ShopifyProduct, Response>(product, {
query: productQuery,
queryParams: { handle: product.handle },
listenQuery: `*[_type == "shopifyProduct" && _id == $id]`,
listenQueryParams: { id: product._id },
parseResponse: getProductFromResponse,
enabled: preview,
})
try {
if (!data) return <NotFound />
return <ProductDetail key={data._id || 'some-key'} product={data} />
} catch (e) {
Sentry.captureException(e)
return <NotFound />
}
}
/**
* Initial Props
*/
export const getStaticProps: GetStaticProps = async (ctx) => {
try {
/** This is wrong, i forget how to get a query param like ?preview=abc in getStaticProps..
* GetStaticProps may not support it... in which case you could parse the window.location
* in the Product component above */
const { params, queryParams } = ctx
const preview = Boolean(queryParams?.preview)
if (!params?.productSlug) return { props: { product: undefined } }
const handle = getParam(params.productSlug)
const variables = { handle }
const [response, shopData] = await Promise.all([
request<Response>(productQuery, variables),
requestShopData(),
])
const product = getProductFromResponse(response)
return { props: { product, shopData, preview }, revalidate: 60 }
} catch (e) {
Sentry.captureException(e)
return { props: {}, revalidate: 1 }
}
}
import { DocumentNode } from 'graphql'
import { useState, useEffect } from 'react'
import { request } from '../qraphql'
import { sanityClient } from '../services/sanity'
interface UseRefetchConfig<DataType, Response> {
/** The initial query that should be refetched */
query: DocumentNode
/** Any params for the initial query */
queryParams?: Record<string, any>
/** The listener query */
listenQuery: string
/** Any params for the initial query */
listenQueryParams?: Record<string, any>
/** An optional function used to extract data from the response */
parseResponse?: (r: Response) => DataType | null
/** An option to enable refetching */
enabled: boolean
}
function useRefetch<DataType, Response>(
initialData: DataType,
config: UseRefetchConfig<DataType, Response>,
) {
const {
query,
queryParams,
listenQuery,
listenQueryParams,
parseResponse,
enabled,
} = config
const [data, setData] = useState(initialData)
const [lastRev, setLastRev] = useState<string | null>(null)
const refetch = async () => {
const result = await request<Response>(query, queryParams)
const newData = parseResponse ? parseResponse(result) : result
setData(newData)
}
/**
* Refetch whenever the queried document's _rev has changed
*/
useEffect(() => {
if (!lastRev) return
refetch()
}, [lastRev])
useEffect(() => {
if (!enabled) return
const subscription = sanityClient
.listen(listenQuery, listenQueryParams)
.subscribe((update) => {
setLastRev(update.result._rev)
})
return () => subscription.unsubscribe()
}, [enabled])
return data
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment