Search code examples
reactjsmeteorfilestack

How to use Meteor.settings in a React Component


I have a React component which is making an API call on init on the client side. I don't want to hard-code my API key (god forbid in the repo), and it's not much better to put it in Meteor.settings.public since that can just be looked up in the console. I want to keep it in Meteor.settings, but then it's invisible to the client. I've tried using a method, but although it appears to work on the server the method call returns undefined on the client.

On the server:

Meteor.methods({
  getFileStackAPIKey: function () {
      if (Meteor.settings.fileStackAPIKey) {
          console.log(Meteor.settings.fileStackAPIKey) // returns: [fileStackAPIKey] correctly
          return Meteor.settings.fileStackAPIKey
      }
      else {
          return {message: "Configure Meteor.settings.fileStackAPIKey to connect to FileStack."}
      }
  }});

On the client:

console.log(Meteor.call('getFileStackAPIKey')); // returns: undefined

I tried to use ReactiveVar and again it set it on the server but was inaccessible on the client. I have the feeling that I'm missing something obvious. Specifically, what I'm trying to make work is FileStack. Their example code shows the API key hard-coded inline. As does the official FileStack React package. This just doesn't seem like a good idea.


Solution

  • It has to do with callbacks. The method result will be in the callback, so what I needed to do on the client was more like this:

    Meteor.call('getFileStackAPIKey', (err, res) => {
        console.log("FileStack API Key: " + res);
    });
    

    But because what I really wanted to do was pass it into the FileStack init (again, on the client side), so I needed to put the following in the constructor for the FileStack object:

    // "this" is the FileStack object we're constructing
    const fileStackObj = this;
    Meteor.call('getFileStackAPIKey', (err, apiKey) => {
        // here we're inside the callback, so we have the resulting API key
        const client = filestack.init(apiKey, clientOptions);
        // these are synchronous actions dependent on the existence of "client"
        // that we could not do outside of the callback
        fileStackObj.state = {
            client,
            picker: action === 'pick' ? client.picker({ ...actionOptions, onUploadDone: fileStackObj.onFinished }) : null,
        };
        fileStackObj.onFinished = fileStackObj.onFinished.bind(fileStackObj);
        fileStackObj.onFail = fileStackObj.onFail.bind(fileStackObj);
    });