首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Shopify嵌入式应用程序-加载不同的页面不能使用nextjs

Shopify嵌入式应用程序-加载不同的页面不能使用nextjs
EN

Stack Overflow用户
提问于 2022-01-13 13:42:38
回答 2查看 1.4K关注 0票数 2

我有以下设置,当使用nextjs路由器加载新页时,由于新页为空,它无法工作。似乎根本没有客户端或基于iframe的导航重定向发生。

我已经成功地使用北极星Link组件从一个页面导航到另一个页面,但这似乎完全重新加载了我的应用程序在iframe。我想使用客户端路由,甚至在没有运气的情况下都遵循了这个示例https://stackoverflow.com/a/63481122/671095

我正在使用名为useAppRoute的自定义钩子来连接shopify-app-bridge的历史,但我不认为这是我想要实现的最好的方法。

_app.js

代码语言:javascript
复制
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>
  );
}

function PolarisLink({ url, children, external, ...rest }) {
  if (external) {
    return (
      <a href={url} {...rest}>
        {children}
      </a>
    );
  }
  const redirect = useAppRoute();
  return (
    <span
      onClick={(e) => {
        console.log("redirected");
        e.preventDefault();
        e.stopPropagation();
        redirect(url);
      }}
    >
      <a {...rest}>{children}</a>
    </span>
  );
}

class MyApp extends App {
  render() {
    const { Component, pageProps, host, shop } = this.props;
    console.log(host);
    console.log(shop);
    return (
      <AppProvider i18n={translations} linkComponent={PolarisLink}>
        <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;

useAppRoute.js

代码语言:javascript
复制
import { useRouter } from "next/router";
import { useAppBridge } from "@shopify/app-bridge-react";
import { History } from "@shopify/app-bridge/actions";

export function useAppRoute() {
  const app = useAppBridge();
  const router = useRouter();
  const history = History.create(app);
  return (path) => {
    const [, asPath] = router.asPath.split("?");
    const pagePath = path.replace(/\/\d+/g, "/[id]");

    router.push(pagePath, `${path}?${asPath}`).then(() => {
      history.dispatch(History.Action.REPLACE, path);
    });
  };
}

RoutePropigator.js

代码语言:javascript
复制
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示例

代码语言:javascript
复制
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;
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-01-18 05:41:06

因此,解决这一问题的解决方案首先基本实现了_app.jsRoutePropigater代码示例,这里列出了https://github.com/carstenlebek/shopify-node-app-starter

另外,我还必须将我的节点包更新为与这个初学者包示例相同的版本。希望这对其他人有帮助

票数 0
EN

Stack Overflow用户

发布于 2022-01-18 01:40:21

我在RoutePropagator上尝试过类似的方法,但是订阅实际上并不能可靠地启动页面更改。

我只是不认为Shopify将支持NextJS -特别是随着CLI工具的改变,现在脚手架是一个定制的构建,而不是使用NextJS + Koa。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70697595

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档