App Bridge, 1.27 useAppBridge()

Solved
HunkyBill
Shopify Expert
4509 46 492

I am trying to use the hook for App Bridge but it is blowing chunks because I don't know. Please assist. So I load the useAppBridge. I then call it. I then try and use it. But the browser barks back at me this Uncaught Error. I was assuming the call to the hook useAppBridge, would return an App Bridge instance. Apparently, I was wrong. What is the deal here?

 

    Uncaught Error: No AppBridge context provided. Your component must be wrapped in an AppBridge <Context> component.useAppBridge

      useAppBridge.js:16

 

 

import { Provider, TitleBar, useAppBridge } from '@shopify/app-bridge-react';
import { getSessionToken } from '@shopify/app-bridge-utils';

const instance = axios.create();
export default instance;

function MyApp() {
  const [status, setStatus] = useState();
  const app = useAppBridge();
  instance.interceptors.request.use(
    function (config) {
      return getSessionToken(app)  // requires an App Bridge instance
        .then((token) => {
          config.headers['Authorization'] = `Bearer ${token}`;
          console.log("Token from callback ", token);
          return config;
        });
    }
  );

 

 

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
0 Likes
Greg_Kujawa
Shopify Partner
1016 83 238

What happens when you try the sample that's listed in the Shopify docs? https://shopify.dev/tools/app-bridge/react-components/provider 

Specifically, this one sample. I'm still stuck in the Dark Ages using the Embedded App SDK and haven't played much with the App Bridge SDK...

import React from 'react';
import {Provider, useAppBridge} from '@shopify/app-bridge-react';
function MyFunctionalComponent() {
  const app = useAppBridge();
  return (
    <div>
      {(app) => {
        // Do something with App Bridge `app` instance...
        if (app) {
          app.getState().then((state) => console.log(state));
        }
        return <span>Hello world!</span>;
      }}
    </div>
  );
};
function MyApp() {
  const config = {apiKey: '12345', shopOrigin: shopOrigin};
  return (
    <Provider config={config}>
      <MyFunctionalComponent />
    </Provider>
  );
}
const root = document.createElement('div');
document.body.appendChild(root);
ReactDOM.render(<MyApp />, root);

 

0 Likes
HunkyBill
Shopify Expert
4509 46 492

That example fails. Shopify is sloppy in their examples BTW. As a brief explanation of that, note that they use a ReactDOM render call, but there is no import of ReactDOM. So that tells you how much care they took with this concept. Nearly none I suspect. So we need to be careful of copy and pasting their example code!!

Simply put. If I use an old school way of dealing with App Bridge, I do indeed get working code. For example, this code works:

 

 

import createApp from '@shopify/app-bridge';
window.app = createApp({
  apiKey: data.apiKey,
  shopOrigin: data.shopOrigin,
});
console.log("What is a window.app? ", window.app);

 

 

 

But this more modern code, supposedly in place, does not work. And that is what I am curious about.

 

 

import { Provider, TitleBar, useAppBridge } from '@shopify/app-bridge-react';
function MyApp() {
  const app = useAppBridge();
  console.log("And what is App from useAppBridge: ", app);

 

 

So in the one case, I get an App, in the other, errors.

    Uncaught Error: No AppBridge context provided. Your component must be wrapped in an AppBridge <Context> component.

I would like to know why that is. Seems simple enough. I am frustrated because my App only works when I load it after installing it. The install flow is broken due to something internal at Shopify, and my App during install ends up OUTSIDE an iframe, likely because App Bridge.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
0 Likes
HunkyBill
Shopify Expert
4509 46 492

This is an accepted solution.

Solved. Just had to ensure any call to useAppBridge() is in a component already a child of the Provider component, which instantiates App Bridge.

Custom Shopify Apps built just for you! hunkybill@gmail.com http://www.resistorsoftware.com
Icarus_
Tourist
7 0 2

@HunkyBill I still have an simular problem

I have this code for axios:

const instance = Axios.create();

  instance.interceptors.request.use(function (config) {

    return getSessionToken(window.app).then((token) => {

    config.headers["Authorization"] = `Bearer ${token}`;

    return config;

  });

});

However that is thrwing the following error:

session-token.js?24e7:65 Uncaught (in promise) TypeError: Cannot read property 'subscribe' of undefined
at eval (session-token.js?24e7:65)
at new Promise (<anonymous>)
at eval (session-token.js?24e7:64)
at step (session-token.js?24e7:52)
at Object.eval [as next] (session-token.js?24e7:33)
at eval (session-token.js?24e7:27)
at new Promise (<anonymous>)
at __awaiter (session-token.js?24e7:23)
at getSessionToken (session-token.js?24e7:62)
at eval (install.js?9ca1:8)

On my _app I have component inside the Provider as you recommended.

 

function MyProvider(props) {
const app = useAppBridge();

const client = new ApolloClient({
fetch: authenticatedFetch(app),
fetchOptions: {
credentials: "include",
},
});

const Component = props.Component;

return (
<ApolloProvider client={client}>
<Component {...props} />
</ApolloProvider>
);
}

class MyApp extends App {
render() {
const { Component, pageProps, shopOrigin } = this.props;
return (
<AppProvider i18n={translations}>
<Provider
config={{
apiKey: API_KEY,
shopOrigin: shopOrigin,
forceRedirect: true,
}}
>
<ClientRouter />
<MyProvider
Component={Component}
{...pageProps}
shopOrigin={shopOrigin}
/>
</Provider>
</AppProvider>
);
}
}

MyApp.getInitialProps = async ({ ctx }) => {
return {
shopOrigin: ctx.query.shop,
};
};

export default MyApp;