typescript - Skicka som Props vs Extrahera Cache Apollo Client Nextjs
Jag postade detta i apollo-client-repot, men tänkte att jag skulle fråga på Stack Overflow också
Hej! Jag är ny på Apollo (och GraphQL som helhet) och har några frågor om SSR/SSG. Jag vet konceptuellt vad SSR/SSG är och hur det fungerar, men inte så mycket med Apollo-klienten.
Jag har försökt att söka och genomsöka webben för att hitta rätt sätt att göra detta och har sett båda versionerna med lite förklaring till varför, så mitt mål med detta inlägg är att ha en plats att peka på och säga "Detta är varför man gör det ena istället för det andra".
Vilka är fördelarna/nackdelarna med att göra
Det här är en blandning av TypeScript och pseudo-kod, snälla kritisera inte syntaxen, tack
// apolloClient.ts
const client = new ApolloClient({
link: new HttpLink({ uri: '/graphql' }),
cache: new InMemoryCache(),
});
// component.tsx
import client from '../apolloClient';
const Component: FunctionalComponent = ({ data }) => {
...
}
export const getServerSideProps: GetServerSideProps = async () => {
const { data } = client.query(...);
return {
props: { data }
}
}
// app.tsx
import client from './client';
const MyApp: NextComponentType<AppContext, AppInitialProps, AppProps> = ({ Component, pageProps }) => (
<ApolloProvider client={client}>
<Component {...pageProps} />
</ApolloProvider>
);
VS
// apolloClient.ts
const createClient = () => new ApolloClient({
link: new HttpLink({ uri: '/graphql' }),
cache: new InMemoryCache(),
ssrMode: typeof window === 'undefined',
});
let client: ApolloClient<NormalizedCacheObject>;
const initalizeApollo = (initalState?: NormalizedCacheObject) => {
const apolloClient = client ?? createClient();
if (initalState) {
apolloClient.cache.restore({
...apolloClient.cache.extract(),
...initalState,
});
}
if (typeof window === 'undefined') return apolloClient;
client ??= apolloClient;
return client;
}
const useApollo = (initalState?: NormalizedCacheObject) => useMemo(() => initalizeApollo(initalState), [initalState]);
// component.tsx
import { useQuery } from 'apollo-client';
import useApollo from '../apolloClient';
const Component = () => {
const { data } = useQuery(...);
}
export const getServerSideProps: GetServerSideProps = async () => {
const client = useApollo();
await client.query(...);
return {
props: { initalApolloState: client.cache.extract() }
}
}
// app.tsx
const MyApp: NextComponentType<AppContext, AppInitialProps, AppProps> = ({ Component, pageProps }) => {
const client = useApollo(pageProps.initalApolloState);
return (
<ApolloProvider client={client}>
<Component {...pageProps} />
</ApolloProvider>
)
};
Detta är min egen "jag förstår inte"-del av denna diskussion
För mig verkar det som att om man gör det på det andra sättet (med SSR?) måste man köra frågor två gånger och skriva mycket extra kod för att få samma effekt? Vilka är prestanda-/säkerhets-/några fördelar alls med någon av metoderna.
Tack!
Svar #1
Ditt första tillvägagångssätt är mer i linje med vad Next försöker göra. Det vill hämta data vid byggtid för sidor via getStaticProps (SSG) eller getServerSideProps (SSR). Idén är att det ska generera sidor på servern statiskt när det är möjligt.
Apollo Client behöver inte refereras i getStaticProps/getServerSideProps-anropet. Jag tror att du skulle klara dig med att använda Context och inte ens behöva Apollo Client på det sätt som din kod är skriven.
Där jag använder Apollo i Next-appar är när jag behöver hämta data till komponenter. Next har egentligen inget svar på det, men det är något som Apollo gör väldigt bra. Ett bra användningsområde är en meny som visas på varje sida. Du vill inte utlösa en webbplatsomfattande statisk återgenerering om du ändrar ett menyalternativ. Apollo håller alla sidor uppdaterade och kommer inte att få Next att rendrera igen.
Översikt över vad jag har gjort i detta svar.