在具有动态创建路径的 SSG NextJS 站点上使用 initialApolloState
Using initialApolloState on a SSG NextJS site with dynamically created paths
我已经根据 this official Vercel starter example 重新配置了我的应用程序,我已经达到了缓存数据并设置为 initialApolloState
执行 getInitialProps
中的查询的地步], 但我无法弄清楚如何从每个页面上的这个对象中提取数据。
我的页面是从 getStaticPaths
动态创建的,它查询设置为查询 REST API 端点的 GraphQL API。在我的旧配置中(不允许 SSG,这就是我必须重新配置的原因),getStaticProps
函数使用页面 ID 参数来查询具有该特定 ID 的数据并获取该页面所需的所有数据和将它们设置为道具。然而,这个新设置似乎将数据设置为 initialApolloState
对象,ID 附加到对象名称本身。
例如,其中一个道具对象被命名为 TourDossier:33887
,所以我不知道当它在每个页面上都有唯一名称时我应该如何从该对象中提取任何数据。页面道具在每个页面上都有唯一的名称,因为 ID 附加到道具本身,这使得无法以一般方式访问此数据。
我想我只是不知道在使用上面列出的官方示例使用 Apollo 和 SSG 时应该如何提取数据。该示例非常简单,在 getStaticProps
查询中使用 getStaticPaths
和路径中的 ID 参数时似乎还有另一层复杂性。
任何帮助或文档阅读将不胜感激。
编辑:这是我使用 getStaticPaths
和 getStaticProps
动态创建的页面
import { initializeApollo } from "../../apollo/client";
import NavBar from "../../widgets/NavBar";
import { useRouter } from "next/router";
import { useQuery } from "@apollo/client";
import {
GET_TOURS,
GET_TOUR_DOSSIER,
GET_ITIN_DOSSIER,
GET_MAP_ROUTES,
GET_MAP_ACTIVITIES,
GET_MAP_TRANSPORT,
GET_MAP_ACCOM,
} from "../../util/gql";
import TourMain from "../../widgets/TourMain";
const Tour = (props) => {
const router = useRouter();
// This returns 'undefined'.
const data = useQuery(GET_TOUR_DOSSIER);
return (
<div>
<NavBar />
// Passing these as props does not work since these objects
// all have unique IDs based on the query (eg: tourDossier:33887)
<TourMain
tour={initialApolloState.tourDossier}
itin={initialApolloState.itinDossier}
mapRoutes={initialApolloState.mapRoutes}
mapAccom={initialApolloState.mapAccom}
mapActivities={initialApolloState.mapActivities}
mapTransport={initialApolloState.mapTransport}
/>
</div>
);
};
export async function getStaticPaths() {
const apolloClient = initializeApollo();
const tours = await apolloClient.query({
query: GET_TOURS,
});
const paths = tours.data.tours.map((tour) => `/tours/${tour.id}`);
// { fallback: false } means other routes should 404.
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
const apolloClient = initializeApollo();
const tourVars = { id: params.id };
const tourDossier = await apolloClient.query({
query: GET_TOUR_DOSSIER,
variables: tourVars,
});
const itinVars = { id: tourDossier.data.tourDossier.itinerary[0].id };
await apolloClient.query({
query: GET_ITIN_DOSSIER,
variables: itinVars,
});
await apolloClient.query({
query: GET_MAP_ACCOM,
variables: itinVars,
});
await apolloClient.query({
query: GET_MAP_ACTIVITIES,
variables: itinVars,
});
const mapTransport = await apolloClient.query({
query: GET_MAP_TRANSPORT,
variables: itinVars,
});
// Parse mapTransport array to coordinate string which can be consumed
// by Mapbox Directions API.
const coords = mapTransport.data.mapTransport.map((route) =>
route
.reduce(
(str, place) =>
`${str};${place.coordinates[0]},${place.coordinates[1]}`,
""
)
.substring(1)
);
const routesVars = { coords };
await apolloClient.query({
query: GET_MAP_ROUTES,
variables: routesVars,
});
// Pass tour and itinerary data to the page via props.
return {
props: {
initialApolloState: apolloClient.cache.extract(),
},
};
}
export default Tour;
我不确定我是否应该查询缓存以获取页面道具,或者我是否应该能够以某种方式从 initialApolloState
中提取数据,即使对象全部具有基于查询 ID 的唯一名称。
您需要在 getStaticProps
和 React 组件中进行相同的查询(包括变量)。
Apollo 也对查询和变量进行缓存,因此具有不同变量的查询具有不同的缓存。
更改 useQuery
以包含与 getStaticProps
中的查询相同的变量。
const data = useQuery(GET_TOUR_DOSSIER, {
variables: { id: router.query.id }
});
我已经根据 this official Vercel starter example 重新配置了我的应用程序,我已经达到了缓存数据并设置为 initialApolloState
执行 getInitialProps
中的查询的地步], 但我无法弄清楚如何从每个页面上的这个对象中提取数据。
我的页面是从 getStaticPaths
动态创建的,它查询设置为查询 REST API 端点的 GraphQL API。在我的旧配置中(不允许 SSG,这就是我必须重新配置的原因),getStaticProps
函数使用页面 ID 参数来查询具有该特定 ID 的数据并获取该页面所需的所有数据和将它们设置为道具。然而,这个新设置似乎将数据设置为 initialApolloState
对象,ID 附加到对象名称本身。
例如,其中一个道具对象被命名为 TourDossier:33887
,所以我不知道当它在每个页面上都有唯一名称时我应该如何从该对象中提取任何数据。页面道具在每个页面上都有唯一的名称,因为 ID 附加到道具本身,这使得无法以一般方式访问此数据。
我想我只是不知道在使用上面列出的官方示例使用 Apollo 和 SSG 时应该如何提取数据。该示例非常简单,在 getStaticProps
查询中使用 getStaticPaths
和路径中的 ID 参数时似乎还有另一层复杂性。
任何帮助或文档阅读将不胜感激。
编辑:这是我使用 getStaticPaths
和 getStaticProps
import { initializeApollo } from "../../apollo/client";
import NavBar from "../../widgets/NavBar";
import { useRouter } from "next/router";
import { useQuery } from "@apollo/client";
import {
GET_TOURS,
GET_TOUR_DOSSIER,
GET_ITIN_DOSSIER,
GET_MAP_ROUTES,
GET_MAP_ACTIVITIES,
GET_MAP_TRANSPORT,
GET_MAP_ACCOM,
} from "../../util/gql";
import TourMain from "../../widgets/TourMain";
const Tour = (props) => {
const router = useRouter();
// This returns 'undefined'.
const data = useQuery(GET_TOUR_DOSSIER);
return (
<div>
<NavBar />
// Passing these as props does not work since these objects
// all have unique IDs based on the query (eg: tourDossier:33887)
<TourMain
tour={initialApolloState.tourDossier}
itin={initialApolloState.itinDossier}
mapRoutes={initialApolloState.mapRoutes}
mapAccom={initialApolloState.mapAccom}
mapActivities={initialApolloState.mapActivities}
mapTransport={initialApolloState.mapTransport}
/>
</div>
);
};
export async function getStaticPaths() {
const apolloClient = initializeApollo();
const tours = await apolloClient.query({
query: GET_TOURS,
});
const paths = tours.data.tours.map((tour) => `/tours/${tour.id}`);
// { fallback: false } means other routes should 404.
return { paths, fallback: false };
}
export async function getStaticProps({ params }) {
const apolloClient = initializeApollo();
const tourVars = { id: params.id };
const tourDossier = await apolloClient.query({
query: GET_TOUR_DOSSIER,
variables: tourVars,
});
const itinVars = { id: tourDossier.data.tourDossier.itinerary[0].id };
await apolloClient.query({
query: GET_ITIN_DOSSIER,
variables: itinVars,
});
await apolloClient.query({
query: GET_MAP_ACCOM,
variables: itinVars,
});
await apolloClient.query({
query: GET_MAP_ACTIVITIES,
variables: itinVars,
});
const mapTransport = await apolloClient.query({
query: GET_MAP_TRANSPORT,
variables: itinVars,
});
// Parse mapTransport array to coordinate string which can be consumed
// by Mapbox Directions API.
const coords = mapTransport.data.mapTransport.map((route) =>
route
.reduce(
(str, place) =>
`${str};${place.coordinates[0]},${place.coordinates[1]}`,
""
)
.substring(1)
);
const routesVars = { coords };
await apolloClient.query({
query: GET_MAP_ROUTES,
variables: routesVars,
});
// Pass tour and itinerary data to the page via props.
return {
props: {
initialApolloState: apolloClient.cache.extract(),
},
};
}
export default Tour;
我不确定我是否应该查询缓存以获取页面道具,或者我是否应该能够以某种方式从 initialApolloState
中提取数据,即使对象全部具有基于查询 ID 的唯一名称。
您需要在 getStaticProps
和 React 组件中进行相同的查询(包括变量)。
Apollo 也对查询和变量进行缓存,因此具有不同变量的查询具有不同的缓存。
更改 useQuery
以包含与 getStaticProps
中的查询相同的变量。
const data = useQuery(GET_TOUR_DOSSIER, {
variables: { id: router.query.id }
});