繁体   English   中英

嵌入式 shopify 应用程序中的客户端路由

[英]Client-side routing in an embedded shopify app

我正在尝试在嵌入式 shopify 应用程序中使用react-router启用客户端路由。 我使用了 Shopify 中的条指南,但我不清楚./Routes文件中应该包含什么。 我试图在 Stack overflow 或博客上搜索类似的问题,但那里的信息有点过时了。

我的代码:App.jsx:

import {
  ApolloClient,
  ApolloProvider,
  HttpLink,
  InMemoryCache,
} from "@apollo/client";
import {
  Provider as AppBridgeProvider,
  useAppBridge,
} from "@shopify/app-bridge-react";
import { authenticatedFetch } from "@shopify/app-bridge-utils";
import { Redirect } from "@shopify/app-bridge/actions";
import { AppProvider as PolarisProvider } from "@shopify/polaris";
import translations from "@shopify/polaris/locales/en.json";
import "@shopify/polaris/build/esm/styles.css";

import {useMemo} from 'react';
import {useLocation, useNavigate, BrowserRouter, RouterProvider} from 'react-router-dom';

import { HomePage } from "./components/HomePage";
import Routes from './Routes';

function App() {
  const navigate = useNavigate();
  const location = useLocation();
  const history = useMemo(
    () => ({replace: (path) => navigate(path, {replace: true})}),
    [navigate],
  );
  console.log(new URLSearchParams(document.location.search).get("host"))  
  const router = useMemo(
    () => ({
      location,
      history,
    }),
    [location, history],
  );
  return (
    <PolarisProvider i18n={translations}>
      <AppBridgeProvider
        config={{
          apiKey: process.env.SHOPIFY_API_KEY,
          host: new URLSearchParams(document.location.search).get("host"),
          forceRedirect: true,
        }}
        router={router}
      >
        <MyProvider>
            <Routes />
        </MyProvider>
      </AppBridgeProvider>
    </PolarisProvider>
  );
}

function MyProvider({ children }) {
  const app = useAppBridge();

  const client = new ApolloClient({
    cache: new InMemoryCache(),
    link: new HttpLink({
      credentials: "include",
      fetch: userLoggedInFetch(app),
    }),
  });

  return <ApolloProvider client={client}>{children}</ApolloProvider>;
}

export 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;
  };
}

export default function AppWrapper() {
  return (
    <BrowserRouter>
      <App />
    </BrowserRouter>
  );
}

./Routes.jsx

import React from 'react';
import {createBrowserRouter} from "react-router-dom";
import { HomePage } from './components/HomePage';
import { Instructions } from './components/Instructions';

export default function Routes() { 
    const routes = createBrowserRouter([
        {
        path: "/",
        element: <HomePage />,
        },
        {
            path: "/statistics",
            element: <HomePage />,
        },
        {
            path: "/integration",
            element: <Instructions />,
        }
    ]);

    return  routes
}

非常感谢任何帮助:-)

我认为文档中的重要说明是:

如果您使用的是 React Router,请确保 Provider 是路由器组件的子组件。

代码:

 export function MyApp() { const config = { apiKey: '12345', host: host }; const navigate = useNavigate(); const location = useLocation(); const history = useMemo( () => ({ replace: (path) => navigate(path, { replace: true })}), [navigate], ); const router = useMemo( () => ({ location, history, }), [location, history], ); return ( <Provider config={config} router={router} > <Routes /> </Provider> ); } export default function AppWrapper() { return ( <BrowserRouter> // <-- Router wraps App <App /> </BrowserRouter> ); }

这是因为App组件必然需要从 ReactTree 的更高层提供给它的路由上下文,因此它可以使用useNavigateuseLocation挂钩并将history object 代理到navigate function。

此时Routes组件可以是任意渲染一些路由的React组件,进行匹配渲染。 对于您的情况,您不能使用createBrowserRouter并在尝试使用它的App组件下方定义路由器。 在上面的AppWrapper示例中使用旧的BrowserRouterRoutes是一个组件,可以呈现您想要的路由。

例子

import React from 'react';
import { useRoutes } from "react-router-dom";
import { HomePage } from './components/HomePage';
import { Instructions } from './components/Instructions';

export default function Routes() { 
  const routes = useRoutes([
    { path: "/", element: <HomePage /> },
    { path: "/statistics", element: <HomePage /> },
    { path: "/integration", element: <Instructions /> }.
  ]);

  return routes;
}

...

...
import Routes from './Routes';

function App() {
  const navigate = useNavigate();
  const location = useLocation();

  const history = useMemo(
    () => ({replace: (path) => navigate(path, {replace: true})}),
    [navigate],
  );

  const router = useMemo(
    () => ({
      location,
      history,
    }),
    [location, history],
  );

  return (
    <PolarisProvider i18n={translations}>
      <AppBridgeProvider
        config={{
          apiKey: process.env.SHOPIFY_API_KEY,
          host: new URLSearchParams(document.location.search).get("host"),
          forceRedirect: true,
        }}
        router={router}
      >
        <MyProvider>
          <Routes />
        </MyProvider>
      </AppBridgeProvider>
    </PolarisProvider>
  );
}

选择

如果您想使用新的react-router-dom@6.4数据 API,那么以下重构可能适合您。 创建新的数据连接BrowserRouter但重构路由,使App呈现为布局路由(即它在Route上呈现,并且它本身呈现嵌套路由的Outlet以将其内容呈现到)。

例子:

应用程序

...
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
...

function App() {
  const navigate = useNavigate();
  const location = useLocation();

  const history = useMemo(
    () => ({replace: (path) => navigate(path, {replace: true})}),
    [navigate],
  );

  const router = useMemo(
    () => ({
      location,
      history,
    }),
    [location, history],
  );

  return (
    <PolarisProvider i18n={translations}>
      <AppBridgeProvider
        config={{
          apiKey: process.env.SHOPIFY_API_KEY,
          host: new URLSearchParams(document.location.search).get("host"),
          forceRedirect: true,
        }}
        router={router}
      >
        <MyProvider>
          <Outlet />
        </MyProvider>
      </AppBridgeProvider>
    </PolarisProvider>
  );
}

export default App;

创建Router

import React from 'react';
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import App from './path/to/App';
import { HomePage } from './components/HomePage';
import { Instructions } from './components/Instructions';

const router = createBrowserRouter([
  {
    path="/",
    element={<App />}
    children: [
      {
        index: true,
        element: <HomePage />,
      },
      {
        path: "/statistics",
        element: <HomePage />,
      },
      {
        path: "/integration",
        element: <Instructions />,
      }
    ],
  },
]);

export default function Router() {
  return <RouterProvider router={router} />;
}

...

现在导入并渲染路由器:

import Router from '..path/to/Router';

...

<Router />

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM