Polaris-react: Undefined `this.context.polaris`

Created on 10 Dec 2018  路  19Comments  路  Source: Shopify/polaris-react

Issue summary

Following the guide here:
https://polaris.shopify.com/components/structure/app-provider

... I was expecting to be able to redirect a user from within an embedded app using Redirect from @shopify/app-bridge/actions.

Instead I get this error:
Uncaught TypeError: Cannot read property 'appBridge' of undefined

Expected behavior

Page should redirect.

Actual behavior

An error message:

Steps to reproduce the problem

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import {AppProvider, Page, Layout, Card, Stack} from '@shopify/polaris';
import {Redirect} from '@shopify/app-bridge/actions';

export default class TestPage extends React.Component {

    static contextTypes = {
        polaris: PropTypes.object,
    };

    onBackClick () {

        const redirect = Redirect.create(this.context.polaris.appBridge);
        redirect.dispatch(Redirect.Action.APP, '/settings');

    }

    render(){

        return (
            <AppProvider 
                forceRedirect={false} 
                apiKey={App.api_key} 
                shopOrigin={App.shop_origin}>

                <Page 
                        title="Test page"
                        secondaryActions={[
                            {
                                content: 'Back',
                                onAction: () => this.onBackClick()
                            }
                        ]}>
                            <Layout>
                                <Layout.Section>
                                    <p>Test page</p>
                                </Layout.Section>
                            </Layout>

                    </Page>
            </AppProvider>
        );
    }

}

Specifications

  • Are you using the React components? (Y/N): Y
  • Polaris version number: 3.1.1
  • Browser: Chrome
  • Device: Mac
  • Operating System: OSX 10.11.6
馃悰Bug

All 19 comments

馃憢 Thanks for opening your first issue. A contributor should give feedback soon. If you haven鈥檛 already, please check out the contributing guidelines. You can also join #polaris on the Shopify Partners Slack.

@markdavies can you try upgrading to the latest version of Polaris (3.2.1) and see if this error still persists?

Still having the same issue unfortunately

Hi @markdavies, I believe you should be importing everything as PropTypes import * as PropTypes from 'prop-types'; can you let us know if that fixes the issue?

Hi @markdavies I don't seem to have any issues with your example. Are you server side rendering?

Hm, I'm running the exact script from above and see the error. Some more info:

  • Using shopify_app
  • Using webpacker
  • The error happens in development when running webpack-dev-server and also in production (I precompile locally for prod before deploying)
  • My latest package.json after upgrading polaris:
    {
      "name": "test_app",
      "private": true,
      "dependencies": {
        "@rails/webpacker": "3.5",
        "@shopify/app-bridge": "^1.0.0-0",
        "@shopify/polaris": "^3.2.1",
        "axios": "^0.18.0",
        "babel-preset-react": "^6.24.1",
        "clean-webpack-plugin": "^1.0.0",
        "draft-convert": "^2.1.4",
        "draft-js": "^0.10.5",
        "draft-js-export-html": "^1.2.0",
        "prop-types": "^15.6.2",
        "react": "^16.6.3",
        "react-dom": "^16.6.3",
        "react-drop-to-upload": "^1.0.2",
        "react-sortable-hoc": "^0.8.4",
        "turbolinks": "^5.2.0",
        "webpack-cli": "^3.1.2",
        "webpacker-react": "^0.3.2"
      },
      "devDependencies": {
        "webpack-dev-server": "2.11.2"
      }
    }

Hey @markdavies, I've labeled it as a bug. The team will look into it. Thanks.

Over time I have noticed that since Shopify employees have a service where they just snap their fingers and an IT fairy delivers them a computer that works with all Shopify codes for development, they have an advantage over us plebes out running our own systems. We have to maintain and update our computers manually, with our skillsets and we cannot snap our fingers and just have a working development environment. Nice perk when working for Shopify. But it leads to these issues where Shopify employees get to say "it works for me" yet the rest of us scratch our heads wondering how? At least in this case it resulted in a bug report even though for some people it just works.

TL:DR; non-Shopify developers have a tougher time making development machines work with Shopify code than Shopify employees, as they have an internal team dedicated to making sure their computers work in development.

@resistorsoftware do you have any additional reproduction steps for this issue? Is it happening to you as well? While your knowledge of our internal systems is impressive, I don't know that it necessarily contributes to understanding the issue at hand.

@markdavies I suspect the issue with this code is that you are trying to access context in your component that is actually provided by a child it renders, AppProvider. Moving AppProvider to wrap this component, instead of being inside of it, should make it so the context is available:

import React from "react";
import ReactDOM from "react-dom";
import PropTypes from "prop-types";
import { AppProvider, Page, Layout, Card, Stack } from "@shopify/polaris";
import { Redirect } from "@shopify/app-bridge/actions";

export default class TestPage extends React.Component {
  static contextTypes = {
    polaris: PropTypes.object
  };

  onBackClick() {
    const redirect = Redirect.create(this.context.polaris.appBridge);
    redirect.dispatch(Redirect.Action.APP, "/settings");
  }

  render() {
    return (
      <Page
        title="Test page"
        secondaryActions={[
          {
            content: "Back",
            onAction: () => this.onBackClick()
          }
        ]}
      >
        <Layout>
          <Layout.Section>
            <p>Test page</p>
          </Layout.Section>
        </Layout>
      </Page>
    );
  }
}

ReactDOM.render(
  <AppProvider
    forceRedirect={false}
    apiKey={App.api_key}
    shopOrigin={App.shop_origin}
  >
    <TestPage />
  </AppProvider>,
  document.getElementById("app")
);

Once TestPage is inside AppProvider, the context AppProvider puts into the tree will be available.

@lemonmade it was simply this. Public developer points out problem with Polaris. In response thread, Shopify says "hey, works for me no problem!". This leaves an obvious impression. Problem must be with public developer.

My lowly contribution to this was just point out how when that happens, it can often be traced to Shopify has internal controls and tools no one else gets to play with. Can you see how there really is no place to discuss that, but that it directly impacts how we the public can feel about working with Shopify code.

When it works, all is great. When it is borked, heaving chunks, unfinished, and/or a hodge-podge of whatever the code du jour calls for, we can be frustrated.

At last however, you solved it all, easily, concisely, and I appreciate you pointing out that you did not appreciate my analysis of the issue response.

@lemonmade - that was it! Not actually a bug after all, but maybe we could add a line of clarification to the docs.

Thanks for your help.

When I use react-router I get this.context.polaris undefined. Should I use a staticRouter instead? Any examples for react-router?

Hi @sam-cnet, can you provide a code example? I think you need to ensure your <BrowserRouter> is inside your <AppProvider>:

```jsx


{/.../}

Hi @BPScott Thanks for responding. I attached the two files I am working with. It's also worth noting I am using react-router V4. All I can think of right now is to pass the context to a static router, or try this with a the old version of react-router which I will try right after.

scott.zip

Ok I think I've solved the issue. Basically I had to declare the following in each one of my components:

static contextTypes = { polaris: PropTypes.object, };

Originally I had only declared this in my <App/> component and assumed the router would pass context down to the children which is true only my components are not really in any higher order. But where I need this.context.polaris is indeed in a child component. Either way just make sure you're declaring the above in any component that's returning undefined. This is documented in the docs just not very well explained for newbies.

Also had to use Router history because for whatever reason the first matched component in my routes defined context.polaris, but anyother route or component would return undefined. Having my router use history solved this issue.

Good stuff. Thanks for following up with your solution so others can learn from it!

Thanks @BPScott

Hi @sam!
I followed the guidance on https://polaris.shopify.com/components/structure/app-provider.
Redirect should work after button click, no errors appears but no redirect also. I have attached my source code briefly.
Could you tell me why it doesn't works for me?

import * as PropTypes from 'prop-types';
import { Redirect } from "@shopify/app-bridge/actions";

class Help extends Component {
    static contextTypes = {
        polaris: PropTypes.object
    };

    gotoInstallPage = () => {
        const redirect = Redirect.create(this.context.polaris.appBridge);
        return redirect.dispatch(Redirect.Action.APP,'/install');
    }

    render() {
        return(
            <Link monochrome onClick={() => this.gotoInstallPage()}>troubleshooting</Link>
        )
    }
}
Was this page helpful?
0 / 5 - 0 ratings