Last active
October 5, 2021 20:04
-
-
Save good-idea/6a4963c38f857995d4da49c44eb400d0 to your computer and use it in GitHub Desktop.
SK Refetch hook
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 } | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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