Questions and discussions about using the Shopify CLI and Shopify-built libraries.
I've created an embedded react application using the new shopify-app-cli . I'm trying to dispatch a Redirect action but when I attempt to get the appbridge context it comes back undefined.
I've created another project by following the React, Node JS tutorial - and it contains the code below to get the context. This works perfectly within the tutorial project but when used in the CLI created project the appbridge context is undefined.
static contextTypes = { polaris: PropTypes.object, };
redirectToProduct = () => {
const redirect = Redirect.create(this.context.polaris.appBridge);
redirect.dispatch(
Redirect.Action.APP,
'/edit'
);
};
The _app file is different in the new CLI created application. It contains a Provider imported from @shopify/app-bridge-react which takes in a config object containing the API_KEY and shopOrigin. Is the appbridge context accessed through this Provider meaning it's unnessesary to use createApp from shopify/app-bridge as in the code below taken from the Sopify Help Center?
import createApp from '@shopify/app-bridge'; import {Redirect} from '@shopify/app-bridge/actions'; const app = createApp({ apiKey: '12345', shopOrigin: shopOrigin, }); const redirect = Redirect.create(app);
Is there any documentation of @shopify/app-bridge-react that I can refer to as I'm sure I'm missing something obvious?
I'm also using the Loading and Titlebar components from @shopify/app-bridge-react which work great but I'm unsure how to dispatch an action or subscribe to an action when I can't get the appbridge context. I can see via Redux Dev Tools that the START action is automatically dispatched when the Loading component is mounted but how can I manually dispatch the actions START and STOP? As I stated earlier, I can dispatch actions within the framework created within the tutorial project using this.context.polaris.appBridge as the app context but this doesn't work in the CLI created project.
Solved! Go to the solution
This is an accepted solution.
Hi Paul,
FYI, The fix had been included the v1.6.7 release of app-bridge.
To learn more visit the Shopify Help Center or the Community Blog.
Hi there,
Accessing the app instance from the Provider from @shopify/app-bridge-react is slightly different - documentation is coming very soon.
Can you try the following code?
import {AppBridgeContext} from '@shopify/app-bridge-react/context'; class MyComponent extends React.Component { static contextType = AppBridgeContext; redirectToProduct = () => {
// The app instance is accessible through the context const redirect = Redirect.create(this.context); redirect.dispatch( Redirect.Action.APP, '/edit' ); }; }
Trish | Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog
Hi Trish
Thanks for a lot for the help. Unfortunately, I'd already tried this over the weekend after finding the AppBridgeContext exported in context.js in app-bridge-react, but the context is always null.
I've created a simple index.js page to demonstrate and console logged this.context. I haven't amended the _app.js file. Interestingly, pageProps in _app.js is undefined - what is this for and should it have a value?
// index.js import React, { Component } from "react"; import { Page, Heading, Button } from "@shopify/polaris"; import { AppBridgeContext } from "@shopify/app-bridge-react/context"; import { Redirect } from '@shopify/app-bridge/actions'; class MyComponent extends Component { static contextType = AppBridgeContext; redirectToProduct = () => { console.log('btn clicked',this.context); // returns null // The app instance is accessible through the context const redirect = Redirect.create(this.context); redirect.dispatch(Redirect.Action.APP, "/edit"); }; render() { console.log('render',this.context); // returns null return ( <Page> <Heading>Shopify app with Node and React</Heading> <Button onClick={this.redirectToProduct}>Edit</Button> </Page> ); } } export default MyComponent;
// _app.js import ApolloClient from "apollo-boost"; import { ApolloProvider } from "react-apollo"; import App, { Container } from "next/app"; import { AppProvider } from "@shopify/polaris"; import { Provider } from "@shopify/app-bridge-react"; import "@shopify/polaris/styles.css"; const client = new ApolloClient({ fetchOptions: { credentials: "include" } }); class MyApp extends App { static async getInitialProps(server) { const shopOrigin = server.ctx.query.shop; return { shopOrigin }; } render() { const { Component, pageProps, shopOrigin } = this.props; return ( <Container> <AppProvider> <Provider config={{ apiKey: API_KEY, shopOrigin: shopOrigin, forceRedirect: true }} > <ApolloProvider client={client}> <Component {...pageProps} shopOrigin={shopOrigin} /> </ApolloProvider> </Provider> </AppProvider> </Container> ); } }
export default MyApp;
This is my package.json file.
{ "name": "shopify-node-app", "version": "1.0.0", "description": "Shopify's node app for CLI tool", "scripts": { "test": "jest", "dev": "NODE_ENV=development nodemon ./server/index.js --watch ./server/index.js", "build": "next build", "start": "NODE_ENV=production node ./server/index.js", "generate-page": "node scripts/index.js generate-page", "generate-recurring-billing": "node scripts/index.js generate-recurring-billing", "generate-one-time-billing": "node scripts/index.js generate-one-time-billing", "generate-webhook": "node scripts/index.js generate-webhook" }, "repository": { "type": "git", "url": "git+https://github.com/Shopify/shopify-node-app.git" }, "author": "Shopify Inc.", "license": "MIT", "bugs": { "url": "https://github.com/shopify/shopify-node-app/issues" }, "jest": { "clearMocks": true }, "dependencies": { "@babel/core": "7.3.4", "@babel/polyfill": "^7.4.3", "@babel/register": "^7.4.0", "@shopify/app-bridge-react": "^1.5.3", "@shopify/koa-shopify-auth": "^3.1.28", "@shopify/koa-shopify-graphql-proxy": "^3.1.1", "@shopify/koa-shopify-webhooks": "^1.1.8", "@shopify/polaris": "^3.16.0", "@zeit/next-css": "^1.0.1", "apollo-boost": "^0.4.3", "babel-preset-env": "^1.7.0", "dotenv": "^7.0.0", "graphql": "^14.2.1", "isomorphic-fetch": "^2.1.1", "koa": "^2.7.0", "koa-router": "^7.4.0", "koa-session": "^5.10.1", "lodash.get": "^4.4.2", "next": "^8.1.0", "next-env": "^1.1.0", "react": "^16.8.6", "react-apollo": "^2.5.6", "react-dom": "^16.8.6" }, "devDependencies": { "@babel/plugin-transform-runtime": "^7.4.3", "@babel/preset-stage-3": "^7.0.0", "babel-jest": "24.1.0", "babel-register": "^6.26.0", "enzyme": "3.4.3", "enzyme-adapter-react-16": "1.2.0", "husky": "^2.2.0", "jest": "24.1.0", "lint-staged": "^8.1.6", "nodemon": "^1.18.11", "prettier": "1.17.0", "react-addons-test-utils": "15.6.2", "react-test-renderer": "16.4.2" }, "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*.{js,css,json,md}": [ "prettier --write", "git add" ] } }
Hey clucs123,
Can you paste the code from your index.js file? I just create my own test app and can confirm that the app instance can be accessed through the context. I did not make any changes to the _app.js file.
Here's the full content of my index.js file:
import { Heading, Page } from "@shopify/polaris"; import {AppBridgeContext} from '@shopify/app-bridge-react/context'; import {Redirect} from '@shopify/app-bridge/actions'; class MyComponent extends React.Component { static contextType = AppBridgeContext; redirectToProduct = () => { // The app instance is accessible through the context const redirect = Redirect.create(this.context); redirect.dispatch( Redirect.Action.APP, '/edit' ); }; render() { console.log(this.context); // Outputs the app instance return 'hi'; } } const Index = () => ( <Page> <Heading>Shopify app with Node and React 🎉</Heading> <MyComponent/> </Page> );
Trish | Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog
Hi Trish,
This is my full index.js code. I tried your code but sadly I still get null back. I included a screenshot of the browser console showing what happens when the button is clicked.
Thanks again for the help,
Paul
import React, { Component } from "react"; import { Page, Heading, Button } from "@shopify/polaris"; import { AppBridgeContext } from "@shopify/app-bridge-react/context"; import { Redirect } from '@shopify/app-bridge/actions'; class MyComponent extends Component { static contextType = AppBridgeContext; redirectToProduct = () => { console.log('btn clicked',this.context); // return null // The app instance is accessible through the context const redirect = Redirect.create(this.context); redirect.dispatch(Redirect.Action.APP, "/edit"); }; render() { console.log('render',this.context); // returns null return ( <Page> <Heading>Shopify app with Node and React �</Heading> <Button onClick={this.redirectToProduct}>Edit</Button> </Page> ); } } const Index = () => ( <Page> <MyComponent/> </Page> ); export default Index;
Hi Paul,
I just tried your code and the context is showing up for me.
Could there be something wrong with the configs passed to the Provider? Can you try to hardcode the `shopOrigin` with your test shop's domain (Ex. `myshopname.myshopify.com`) and see if that works?
Trish | Shopify
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit the Shopify Help Center or the Shopify Blog
Hi Trish,
Well, it's good to know that my code does actually work. I agree that it must be a config issue. I've tried hard-coding the config values as you suggested but it still doesn't work. I've also checked the API_KEY and shopOrigin variables are populated correctly by console logging them.
I've noticed if I change the API_KEY or shopOrigin to incorrect values the loading START action isn't dispatched on one of my other pages which contains a Loading component. So it seems the credentials are definitely doing something. The screenshot below shows the loading START action has been dispatched - in this case the credentials are set to their correct values.
Is my _app.js file correct and all package dependencies up to date?
Thanks
Paul
Just to be on the safe side I've created a new app in Shopify and a new project from scratch using the CLI and added the simple test component above. The app runs in the test store but again the context is always null.
// index.js
import { Heading, Page } from "@shopify/polaris"; import {AppBridgeContext} from '@shopify/app-bridge-react/context'; import {Redirect} from '@shopify/app-bridge/actions'; class MyComponent extends React.Component { static contextType = AppBridgeContext; redirectToProduct = () => { // The app instance is accessible through the context const redirect = Redirect.create(this.context); redirect.dispatch( Redirect.Action.APP, '/edit' ); }; render() { console.log(this.context); // Outputs the app instance return 'hi'; } } const Index = () => ( <Page> <Heading>Shopify app with Node and React 🎉</Heading> <MyComponent/> </Page> );
// _app.js import ApolloClient from "apollo-boost"; import { ApolloProvider } from "react-apollo"; import App, { Container } from "next/app"; import { AppProvider } from "@shopify/polaris"; import { Provider } from "@shopify/app-bridge-react"; import "@shopify/polaris/styles.css"; const client = new ApolloClient({ fetchOptions: { credentials: "include" } }); class MyApp extends App { static async getInitialProps(server) { const shopOrigin = server.ctx.query.shop; return { shopOrigin }; } render() { const { Component, pageProps, shopOrigin } = this.props; return ( <Container> <AppProvider> <Provider config={{ apiKey: API_KEY, shopOrigin: shopOrigin, forceRedirect: true }} > <ApolloProvider client={client}> <Component {...pageProps} /> </ApolloProvider> </Provider> </AppProvider> </Container> ); } } export default MyApp;
Try running your app inside Shopify admin.
App Bridge is the connection between your app and Shopify admin and doesn't really work without an Admin Frame.
To learn more visit the Shopify Help Center or the Community Blog.
To echo what Michelle said, this app needs to be rendered within the admin for any context to exist. If you're hitting it from your ngrok URL you won't have any luck accessing App Bridge features.
You can install the app on your development store with this url:
`HTTPS://your-ngrok-url.io/auth?shop=your-development-store.myshopify.com`
To learn more visit the Shopify Help Center or the Community Blog.
Hi Katie
The app has always been running inside in the Shopify Admin. I've console logged the context and as you can see it is null.
So sorry about that @clucs123 ! I'm wondering if you could put your code up on github? I'll try running the whole app to see whats going on.
To learn more visit the Shopify Help Center or the Community Blog.
Hi Katie
https://github.com/clucs123/shopify-react-test
No problem. I haven't amended this project since it was created in the shopify-app-cli, apart from the index.js file and my .env config file.
The .env file obviously isn't on GitHub for security reasons but this is its structure. I've created a couple of other embedded apps now and I haven't had any other issues. All the components seem to work as expected. The Loading component automatically dispatches a START action when mounted for example. I just need to access the context so I can dispatch actions when I want. Thanks for your help, Katie. I'll be so happy when this is resolved!
I don't know if this matters at all but I created the project in Windows 10 using the Ubuntu VM as outlined in the shopify-app-cli readme ... https://github.com/Shopify/shopify-app-cli.
SHOPIFY_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxx SHOPIFY_API_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxx HOST=https://xxxxxxxxx.ngrok.io SHOP=pauls-dev-store.myshopify.com SCOPES=write_products,write_customers,write_draft_orders
no problem @clucs123 I'll take a look today and let you know what I find, it just might take a bit.
To learn more visit the Shopify Help Center or the Community Blog.
hey @clucs123 with some investigation with @Trish_Ta we've figured out the issue!
can you add @babel/preset-env? the package we were using (babel-preset-env) has been moved into that! It solved the issue on both our ends
To learn more visit the Shopify Help Center or the Community Blog.
Hey Katie,
Can I just confirm, do I install the @babel/preset-env package as a dev dependency as per install instructions at https://babeljs.io/docs/en/babel-preset-env ?
Also, do I have to uninstall the babel-preset-env package from the regular dependencies?
Thanks
Paul
Hey Katie
I can see the context written back to the terminal in VSCode but it's still null in the browser but at least we are getting somewhere 🙂
The @babel/preset-env is installed as a regular dependency. If I install it as a dev dependency the context isn't written back to the terminal. I've added my package.json below along with screenshots of the browser console and terminal window.
Thanks again,
Paul.
{ "name": "shopify-node-app", "version": "1.0.0", "description": "Shopify's node app for CLI tool", "scripts": { "test": "jest", "dev": "NODE_ENV=development nodemon ./server/index.js --watch ./server/index.js", "build": "next build", "start": "NODE_ENV=production node ./server/index.js", "generate-page": "node scripts/index.js generate-page", "generate-recurring-billing": "node scripts/index.js generate-recurring-billing", "generate-one-time-billing": "node scripts/index.js generate-one-time-billing", "generate-webhook": "node scripts/index.js generate-webhook" }, "repository": { "type": "git", "url": "git+https://github.com/Shopify/shopify-node-app.git" }, "author": "Shopify Inc.", "license": "MIT", "bugs": { "url": "https://github.com/shopify/shopify-node-app/issues" }, "jest": { "clearMocks": true }, "dependencies": { "@babel/core": "7.3.4", "@babel/polyfill": "^7.4.3", "@babel/preset-env": "^7.5.0", "@babel/register": "^7.4.0", "@shopify/app-bridge-react": "^1.5.3", "@shopify/koa-shopify-auth": "^3.1.28", "@shopify/koa-shopify-graphql-proxy": "^3.1.1", "@shopify/koa-shopify-webhooks": "^1.1.8", "@shopify/polaris": "^3.16.0", "@zeit/next-css": "^1.0.1", "apollo-boost": "^0.4.3", "dotenv": "^7.0.0", "graphql": "^14.2.1", "isomorphic-fetch": "^2.1.1", "koa": "^2.7.0", "koa-router": "^7.4.0", "koa-session": "^5.10.1", "lodash.get": "^4.4.2", "next": "^8.1.0", "next-env": "^1.1.0", "react": "^16.8.6", "react-apollo": "^2.5.6", "react-dom": "^16.8.6" }, "devDependencies": { "@babel/plugin-transform-runtime": "^7.4.3", "@babel/preset-stage-3": "^7.0.0", "babel-jest": "24.1.0", "babel-register": "^6.26.0", "enzyme": "3.4.3", "enzyme-adapter-react-16": "1.2.0", "husky": "^2.2.0", "jest": "24.1.0", "lint-staged": "^8.1.6", "nodemon": "^1.18.11", "prettier": "1.17.0", "react-addons-test-utils": "15.6.2", "react-test-renderer": "16.4.2" }, "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*.{js,css,json,md}": [ "prettier --write", "git add" ] } }
Hi again,
Both Trish and I had success with the changes made. Can you try generating a fresh app from the CLI?
To learn more visit the Shopify Help Center or the Community Blog.
Hey Katie
I created a new project using the CLI and its the same. The chrome dev tools show null for the context but I can see the context written back in the terminal in VSCode. I'm sure its something I'm doing wrong. These are the steps I go through to get the project up and running.
This is all I do to get the app running. I've also created a completely new app in the dashboard and repeated the above but with no luck.
The question is, why can I see the context in the terminal within VSCode but not in the browsers dev tools? I've done a fair bit of googling on this one with no clear answer.
I've created a new git repo for this latest attempt if you wanted to try it.
https://github.com/clucs123/shopify-react-test-v2
I'm fairly sure it's not relevant but as you mentioned babel earlier I thought it worth mentioning that I read on https://babeljs.io/docs/en/babel-preset-stage-3 that all stage presets have been depreciated as of babel v7, and this project uses babel v7 and has preset-stage-3 as a dev dependency.
Many thanks,
Paul
Or for those using Hooks:
import React, { useContext } from 'react'; import { AppBridgeContext } from '@shopify/app-bridge-react/context'; import { Redirect } from '@shopify/app-bridge/actions'; export default (props) => { const polaris = useContext(AppBridgeContext); const redirectToProduct = () => { const redirect = Redirect.create(polaris); redirect.dispatch(Redirect.Action.APP, '/edit'); } }
Hey Markus
Thanks for helping out. I tried the code below based on what you posted and I have the same result. I can see the context in the VSCode terminal but not in the browser console. I'm sure I'm missing something obvious.
I've described the process I go through to create a project using the new CLI in an earlier post and put my last try on GitHub with index.js using useContext as you described. Can you see where I'm going wrong?
Thanks again
Paul
https://github.com/clucs123/shopify-react-test-v2
import { AppBridgeContext } from "@shopify/app-bridge-react/context"; import { Heading, Page, Button } from "@shopify/polaris"; import { Redirect } from "@shopify/app-bridge/actions"; import { useContext } from "react"; export default props => { const polaris = useContext(AppBridgeContext); const redirectToProduct = () => { console.log("btn clicked", polaris); const redirect = Redirect.create(polaris); redirect.dispatch(Redirect.Action.APP, "/edit"); }; console.log("context", polaris); return ( <Page> <Heading>Shopify app with Node and React demo v2 🎉</Heading> <Button onClick={redirectToProduct}>Click Me</Button> </Page> ); };
Hi Paul,
First of all thank you for providing all the details of your current project setup.
This actually help us discover an obscure bug that took some time to track down.
We are in the process of fixing with it with app-bridge, and will update here once the new version is available.
To learn more visit the Shopify Help Center or the Community Blog.
Hi Michelle
Well, I'm just glad I wasn't doing anything too wrong. I'll continue using the app that I've created via the tutorial as that's working as expected.
It'll be good to use the CLI again once the issue is resolved as it potentially saves heaps of time.
Thanks for letting me know and best of luck!
Paul
This is an accepted solution.
Hi Paul,
FYI, The fix had been included the v1.6.7 release of app-bridge.
To learn more visit the Shopify Help Center or the Community Blog.
Hi Michelle
Works a treat! Great to get this sorted.
Thanks for your help.
Paul
Hi Michelle, thanks for the solution as I was struggling with a similar issue for which this solution worked. I wanted to point out that the solution here on using the AppBridgeContext differs from what is in the official docs. The official doc solution https://help.shopify.com/en/api/embedded-apps/app-bridge/react-components/provider
indicates to use
// code from docs https://help.shopify.com/en/api/embedded-apps/app-bridge/react-components/provider
import {Context} from '@shopify/app-bridge-react';
static contextType = Context;
This did not work for me and gave errors about this.app.dispatch not being defined, once I switched to importing AppBridgeContext and setting the contextType to AppBridgeContext I was able to get redirects working appropriately.
// working code from solution
import {AppBridgeContext} from '@shopify/app-bridge-react/context';
static contextType = AppBridgeContext;
If the docs are in fact wrong it would be helpful to get them updated.
Hi Adam, could you provide a more extensive example? and just to confirm, you’re using App Bridge >=1.6.7?
I’m puzzled that you got errors using Context from the main app-bridge-react package, as it’s the exact same object as AppBridgeContext from app-bridge-react/context. Seeing a more extensive example of where you got the error might help me understand.
To learn more visit the Shopify Help Center or the Community Blog.
Hi Iain, sorry for late reply I was on vacation. I was using 1.6.6 at the time of App Bridge. I tried to reproduce the behaviour and was unable to do so in 1.6.8, both context and appbridgecontext give the same results. I'm not sure what was going on before, perhaps there was a different issue like some bad cached built files or something. Since i can't reproduce in latest can probably ignore this. Thanks for looking at it.
@Adam_Hurlburt glad you got it sorted 🙂
To learn more visit the Shopify Help Center or the Community Blog.