Встроенное приложение Shopify - загрузка разных страниц не работает с использованием nextjs
У меня есть следующая настройка: при загрузке новой страницы с помощью маршрутизатора nextjs она не работает, так как новая страница пуста. Кажется, что перенаправление навигации на стороне клиента или iframe вообще не происходит.
Я успешно использовал Polaris
Link
компоненты для перехода со страницы на страницу, но это, похоже, полностью перезагружает мое приложение. Я хотел бы использовать маршрутизацию на стороне клиента и даже безуспешно следовал этому примеру /questions/54896155/stranitsyi-perezagruzhayutsya-vmesto-perenapravleniya-v-prilozhenii-shopify-next/54896167#54896167
_app.js
import {
ApolloClient,
ApolloProvider,
ApolloLink,
HttpLink,
InMemoryCache,
} from "@apollo/client";
import App from "next/app";
import { AppProvider } from "@shopify/polaris";
import { Provider, useAppBridge } from "@shopify/app-bridge-react";
import { authenticatedFetch } from "@shopify/app-bridge-utils";
import { Redirect } from "@shopify/app-bridge/actions";
import "@shopify/polaris/build/esm/styles.css";
import translations from "@shopify/polaris/locales/en.json";
import RoutePropagator from "../components/RoutePropagator";
import { useAppRoute } from "src/hooks/useAppRoute";
import { ShopifySettingsProvider } from "src/contexts/ShopifySettings";
function userLoggedInFetch(app) {
const fetchFunction = authenticatedFetch(app);
return async (uri, options) => {
const response = await fetchFunction(uri, options);
if (
response.headers.get("X-Shopify-API-Request-Failure-Reauthorize") === "1"
) {
const authUrlHeader = response.headers.get(
"X-Shopify-API-Request-Failure-Reauthorize-Url"
);
const redirect = Redirect.create(app);
redirect.dispatch(Redirect.Action.APP, authUrlHeader || `/auth`);
return null;
}
return response;
};
}
function MyProvider(props) {
const app = useAppBridge();
const client = new ApolloClient({
cache: new InMemoryCache(),
link: ApolloLink.split(
(operation) => operation.getContext().clientName === "shopify",
new HttpLink({
uri: "/graphql-shopify",
fetch: userLoggedInFetch(app),
fetchOptions: {
credentials: "include",
},
}),
new HttpLink({ uri: "/graphql" })
),
});
const { shop } = props;
return (
<ApolloProvider client={client}>
<ShopifySettingsProvider shop={shop}>
{props.children}
</ShopifySettingsProvider>
</ApolloProvider>
);
}
class MyApp extends App {
render() {
const { Component, pageProps, host, shop } = this.props;
console.log(host);
console.log(shop);
return (
<AppProvider i18n={translations}>
<Provider
config={{
apiKey: API_KEY,
host: host,
forceRedirect: true,
}}
>
{/* <ClientRouter /> */}
<RoutePropagator />
<MyProvider Component={Component}>
<Component {...pageProps} />
</MyProvider>
</Provider>
</AppProvider>
);
}
}
MyApp.getInitialProps = async ({ ctx }) => {
console.log(ctx);
return {
host: ctx.query.host,
};
};
export default MyApp;
RoutePropigator.js
import React, {useEffect, useContext} from 'react';
import Router, { useRouter } from "next/router";
import { Context as AppBridgeContext } from "@shopify/app-bridge-react";
import { Redirect } from "@shopify/app-bridge/actions";
import { RoutePropagator as ShopifyRoutePropagator } from "@shopify/app-bridge-react";
const RoutePropagator = () => {
const router = useRouter();
const { asPath } = router;
const appBridge = React.useContext(AppBridgeContext);
// Subscribe to appBridge changes - captures appBridge urls
// and sends them to Next.js router. Use useEffect hook to
// load once when component mounted
useEffect(() => {
appBridge.subscribe(Redirect.Action.APP, ({ path }) => {
Router.push(path);
});
}, []);
return appBridge && asPath ? (
<ShopifyRoutePropagator location={asPath} app={appBridge} />
) : null;
}
export default RoutePropagator;
index.js — пример router.push
import React, { useState } from "react";
import Link from "next/link";
import {
Frame,
Page,
Layout,
EmptyState,
Button,
Card,
} from "@shopify/polaris";
import { ResourcePicker, TitleBar } from "@shopify/app-bridge-react";
import store from "store-js";
import ResourceListWithProducts from "../components/elements/ResourceList";
import Sidebar from "../components/Sidebar";
import { useRouter } from 'next/router'
const img = "https://cdn.shopify.com/s/files/1/0757/9955/files/empty-state.svg";
const Index = () => {
const router = useRouter()
const [open, setOpen] = useState(false);
// A constant that defines your app's empty state
const emptyState = !store.get("ids");
const handleSelection = (resources) => {
const idsFromResources = resources.selection.map((product) => product.id);
setOpen(false);
store.set("ids", idsFromResources);
};
return (
<Frame navigation={<Sidebar />}>
<Page>
<TitleBar />
<ResourcePicker
resourceType="Product"
showVariants={false}
open={open}
onSelection={(resources) => handleSelection(resources)}
onCancel={() => setOpen(false)}
/>
{emptyState ? ( // Controls the layout of your app's empty state
<Layout>
<EmptyState heading="Customise your product" image={img}>
<p>Add options to customise your product.<button onClick={() => router.push('/colours')}>Go to colours</button></p>
</EmptyState>
</Layout>
) : (
// Uses the new resource list that retrieves products by IDs
<ResourceListWithProducts />
)}
</Page>
</Frame>
);
};
export default Index;
2 ответа
Итак, решение для решения этой проблемы было первым, чтобы в основном реализовать
_app.js
,
RoutePropigater
пример кода выложен здесь https://github.com/carstenlebek/shopify-node-app-starter
Также, в частности, мне пришлось также обновить пакеты узлов до тех же версий, что и в этом примере стартового пакета. Надеюсь, это поможет другим людям
Я пробовал аналогичный подход с
RoutePropagator
но подписка на самом деле не срабатывает надежно при изменении страницы.
Я просто не думаю, что Shopify будет поддерживать NextJS, особенно с изменением инструмента CLI, который теперь формирует пользовательскую сборку вместо использования NextJS + Koa.