0

I'm new to react and I'm trying to build a basic Shopify app using React and the Polaris React suite.

TL:DR;

How can I prevent a React component from rendering until data has been fetched asynchronously from the server? OR What is the correct method to get a Polaris app to connect to the shopify service?

Full Explanation

The problem is the render function should add the store domain to an attribute on the <AppProvider/> element. Ie. <AppProvider shopOrigin="https://user-store.myshopify.com"/> However, the domain differs depending on the store using the app.

Given that React is rendered on the client side, I need to send a request to the server to retrieve the current store domain. But this happens after the app has rendered:

render() {

    return (
      <AppProvider
        shopOrigin={this.state.shop} {/* Null when first rendered  */}
        debug={true}
      > ... </AppProvider>

This results in the Polaris app atempting to connect to Shopify with a Null value for the shop domain and everything breaks.

I've been able to prevent this by having the render function return Null on the first render but this feels kind of hacky

 render() {   

    if (typeof this.state.shop === 'undefined') {/* true on first render */}
      return null; { /* prevent rendering at this stage */ }

    return (
      <AppProvider
        shopOrigin={this.state.shop}
        debug={true}
      > 

Here is the async function that I'm using to get the domain from the server

 constructor() {
    super();

    this.state = {};
  }

  componentDidMount() {
    this.callApi()
      .then(res => this.setState(res))
      .catch(err => console.log(err));
  }

  callApi = async () => {
    const response = await fetch('/shopify/config');
    const body = await response.json();

    if (response.status !== 200) throw Error(body.message);

    return body;
  };
andrew
  • 9,313
  • 7
  • 30
  • 61
  • Makes no sense that you are waiting around till you can ask for the domain from the server? When would you ever have a Shopify call hit your App without the name of the shop in the payload? All Shopify EASDK setups provide you with the shop. Your use case or how you are using EASDK seem odd. For kicks can you explain briefly what you are trying to do with Polaris? – David Lazar Aug 12 '18 at 03:24
  • @DavidLazar After studying your comment, i looked again at the way I'm doing things. After a POST request to `'https://' + domain + '/admin/oauth/access_token';` I do a `res.redirect('/')` which means i loose the store domain. For that reason I store it in the session. Hence the need for a request to the server to retrieve it. I think I need to get rid of the redirect and serve the app from the `&redirect_uri=https://${appDomain}/shopify/auth` location – andrew Aug 12 '18 at 06:57
  • The idea is to use your session. When you get an oAuth token you persist it along with the store myshopify.com domain name. That way when a merchant clicks into your App, you match the supplied shop name to your DB and get the existing token, setup a session and carry on. – David Lazar Aug 12 '18 at 19:51

1 Answers1

3

A simple way to do this is keeping an 'isLoading' attribute in your component's state, which is initially set to true.

Once your component has finished fetching whatever data it needs to, call this.setState({isLoading: false}).

Then your component's render method should look something like this:

render() {
    const { isLoading } = this.state;

    if (isLoading) {
        return <span>loading...</span>
    }

    return <AppProvider {...props}/>
}

This way your app won't try to connect to the Shopify service until it is done fetching data.

Of course you can make the return value of render whatever you like, maybe put a loading icon/animation in there, or just return an empty <div>.

Henry Woody
  • 14,024
  • 7
  • 39
  • 56
  • Oh this is a fantastic Idea, and it gives the user feedback during the async request that something is happening! Thanks – andrew Aug 12 '18 at 02:13
  • @andrew Of course. It's a nice little trick for any time a component needs to fetch and display data so your app looks good even while fetching. – Henry Woody Aug 12 '18 at 02:15