Created
June 15, 2020 20:40
-
-
Save robabby/4c33ef0ecb8b6d9871dbf2c2d70d752a to your computer and use it in GitHub Desktop.
Apollo Client Examples
This file contains hidden or 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 { typeDefs } from "./schema/resolvers"; | |
import { ApolloClient } from "apollo-client"; | |
import { ApolloLink } from "apollo-link"; | |
import { ApolloProvider } from '@apollo/react-hooks'; | |
import App from "./App"; | |
import { InMemoryCache } from "apollo-cache-inmemory"; | |
import React from "react"; | |
import { createUploadLink } from "apollo-upload-client"; | |
import { getToken } from "./utils/cookies"; | |
import initialQuery from "./schema/queries/isLoggedIn"; | |
import { setContext } from "apollo-link-context"; | |
const token = getToken(); | |
const httpUploadLink = createUploadLink({ | |
uri: `${process.env.REACT_APP_API}/graphql` | |
}); | |
const authLink = setContext((_, { headers }) => { | |
return { | |
headers: { | |
...headers, | |
Authorization: !!token ? `Bearer ${token}` : "", | |
"client-name": "Sherpa [web]", | |
credentials: "include" | |
} | |
}; | |
}); | |
const link = ApolloLink.from([authLink, httpUploadLink]); | |
const cache = new InMemoryCache({ | |
dataIdFromObject: (o) => o.id | |
}); | |
const client = new ApolloClient({ | |
cache, | |
link, | |
typeDefs | |
}); | |
client.writeData({ | |
data: { | |
isLoggedIn: !!token | |
}, | |
}); | |
async function writeInitialQuery() { | |
const token = getToken(); | |
return client.writeQuery({ | |
query: initialQuery, | |
data: { | |
isLoggedIn: !!token | |
} | |
}) | |
} | |
writeInitialQuery(); | |
client.onResetStore(writeInitialQuery); | |
const Root = (props) => { | |
return ( | |
<ApolloProvider client={client}> | |
<App /> | |
</ApolloProvider> | |
); | |
}; | |
export default Root; |
This file contains hidden or 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 React from "react"; | |
import Head from "next/head"; | |
import { ApolloProvider } from "@apollo/react-hooks"; | |
import { ApolloClient } from "apollo-client"; | |
import { InMemoryCache } from "apollo-cache-inmemory"; | |
import fetch from "isomorphic-unfetch"; | |
let apolloClient = null; | |
function createIsomorphLink() { | |
const { createUploadLink } = require("apollo-upload-client"); | |
return createUploadLink({ | |
uri: process.env.GRAPHQL_URI, | |
credentials: "same-origin" | |
}); | |
} | |
/** | |
* Creates and configures the ApolloClient | |
* @param {Object} [initialState={}] | |
*/ | |
function createApolloClient(initialState = {}) { | |
const ssrMode = typeof window === "undefined"; | |
const cache = new InMemoryCache({ | |
dataIdFromObject: o => o.id | |
}).restore(initialState); | |
return new ApolloClient({ | |
ssrMode, | |
link: createIsomorphLink() as any, | |
cache | |
}); | |
} | |
/** | |
* Always creates a new apollo client on the server | |
* Creates or reuses apollo client in the browser. | |
* @param {Object} initialState | |
*/ | |
function initApolloClient(initialState) { | |
// Make sure to create a new client for every server-side request so that data | |
// isn't shared between connections (which would be bad) | |
if (typeof window === "undefined") { | |
return createApolloClient(initialState); | |
} | |
// Reuse client on the client-side | |
if (!apolloClient) { | |
apolloClient = createApolloClient(initialState); | |
} | |
return apolloClient; | |
} | |
/** | |
* Creates and provides the apolloContext | |
* to a next.js PageTree. Use it by wrapping | |
* your PageComponent via HOC pattern. | |
* @param {Function|Class} PageComponent | |
* @param {Object} [config] | |
* @param {Boolean} [config.ssr=true] | |
*/ | |
export function withApollo(PageComponent, { ssr = true } = {}) { | |
const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => { | |
const client = apolloClient || initApolloClient(apolloState); | |
return ( | |
<ApolloProvider client={client}> | |
<PageComponent {...pageProps} /> | |
</ApolloProvider> | |
); | |
}; | |
// Set the correct displayName in development | |
if (process.env.NODE_ENV !== "production") { | |
const displayName = | |
PageComponent.displayName || PageComponent.name || "Component"; | |
if (displayName === "App") { | |
console.warn("This withApollo HOC only works with PageComponents."); | |
} | |
WithApollo.displayName = `withApollo(${displayName})`; | |
} | |
if (ssr || PageComponent.getInitialProps) { | |
WithApollo.getInitialProps = async ctx => { | |
const { AppTree } = ctx; | |
// Initialize ApolloClient, add it to the ctx object so | |
// we can use it in `PageComponent.getInitialProp`. | |
const apolloClient = (ctx.apolloClient = initApolloClient()); | |
// Run wrapped getInitialProps methods | |
let pageProps = {}; | |
if (PageComponent.getInitialProps) { | |
pageProps = await PageComponent.getInitialProps(ctx); | |
} | |
// Only on the server: | |
if (typeof window === "undefined") { | |
// When redirecting, the response is finished. | |
// No point in continuing to render | |
if (ctx.res && ctx.res.finished) { | |
return pageProps; | |
} | |
// Only if ssr is enabled | |
if (ssr) { | |
try { | |
// Run all GraphQL queries | |
const { getDataFromTree } = await import("@apollo/react-ssr"); | |
await getDataFromTree( | |
<AppTree | |
pageProps={{ | |
...pageProps, | |
apolloClient | |
}} | |
/> | |
); | |
} catch (error) { | |
// Prevent Apollo Client GraphQL errors from crashing SSR. | |
// Handle them in components via the data.error prop: | |
// https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error | |
console.error("Error while running `getDataFromTree`", error); | |
} | |
// getDataFromTree does not call componentWillUnmount | |
// head side effect therefore need to be cleared manually | |
Head.rewind(); | |
} | |
} | |
// Extract query data from the Apollo store | |
const apolloState = apolloClient.cache.extract(); | |
return { | |
...pageProps, | |
apolloState | |
}; | |
}; | |
} | |
return WithApollo; | |
} |
This file contains hidden or 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 { ApolloClient } from "apollo-client"; | |
import { ApolloLink } from "apollo-link"; | |
import { InMemoryCache } from "apollo-cache-inmemory"; | |
import { createUploadLink } from "apollo-upload-client"; | |
import { getUserIdFromToken } from "../utils/getUserId"; | |
import initialQuery from "./queries/isLoggedIn"; | |
import { useMemo } from "react"; | |
let apolloClient; | |
function createApolloClient(initialState) { | |
const cache = new InMemoryCache({ | |
dataIdFromObject: o => o.id | |
}); | |
const { isLoggedIn, token } = initialState; | |
const initialData = { | |
id: getUserIdFromToken(token), | |
isLoggedIn, | |
token | |
}; | |
cache.writeData({ data: initialData }); | |
const httpUploadLink = createUploadLink({ | |
uri: process.env.GRAPHQL_URI | |
}); | |
const link = new ApolloLink((operation, forward) => { | |
operation.setContext({ | |
credentials: "same-origin", | |
headers: { | |
"Access-Control-Allow-Origin": "*", | |
Authorization: token ? `Bearer ${token}` : "" | |
} | |
}); | |
return forward(operation); | |
}).concat(httpUploadLink); | |
const client = new ApolloClient({ | |
cache, | |
link, | |
resolvers: {}, | |
ssrMode: typeof window === "undefined" | |
}); | |
client.writeData({ | |
data: initialData | |
}); | |
async function writeInitialQuery() { | |
return client.writeQuery({ | |
query: initialQuery, | |
data: initialData | |
}); | |
} | |
writeInitialQuery(); | |
client.onResetStore(writeInitialQuery); | |
return client; | |
} | |
export function initializeApollo(initialState) { | |
const _apolloClient = apolloClient ?? createApolloClient(initialState); | |
// If your page has Next.js data fetching methods that use Apollo Client, the initial state | |
// gets hydrated here | |
if (initialState) { | |
console.log("initializeApollo - initialState: ", initialState); | |
_apolloClient.cache.restore(initialState); | |
} | |
// For SSG and SSR always create a new Apollo Client | |
if (typeof window === "undefined") return _apolloClient; | |
// Create the Apollo Client once in the client | |
if (!apolloClient) apolloClient = _apolloClient; | |
return _apolloClient; | |
} | |
export function useApollo(initialState) { | |
const store = useMemo(() => initializeApollo(initialState), [initialState]); | |
return store; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment