0

Here is the simple scenario, I am struggling with

apicontainer.js

import mockApi from './mock-api';
import realApi from './api';
function getApi() {
   return Cookies.get('isMock') ? mockApi: realApi;
}
let api = getApi();
export function changeApi() {
    api = getApi();
}
export default api

somepage.js

import api from './path-to/apicontainer';

After the application gets loaded, If set/remove cookie and call changeApi method, will it change the reference dynamically and returns the right api or Is there a better solution?

Chiru
  • 3,661
  • 1
  • 20
  • 30
hashbytes
  • 769
  • 1
  • 8
  • 26
  • 1
    Have you tried this solution already? Does it work? Regardless, why not just call the `getApi()` function every time you want the API? Checking cookies is not an expensive operation. – ethan.roday Mar 27 '18 at 22:27
  • `import api from { apicontainer }` is definitely invalid syntax. Please fix it. Also you're not exporting `api`? – Bergi Mar 27 '18 at 22:30
  • @Bergi I was exporting it, forgot to add it to code snippet. – hashbytes Mar 28 '18 at 21:33

3 Answers3

3

Yes, imported bindings are just references to the exported variables. One does not export the value, one makes the variable itself available (readonly from outside, though).

So you can do

// apicontainer.js
import mockApi from './mock-api';
import realApi from './api';
function getApi() {
   return Cookies.get('isMock') ? mockApi: realApi;
}
let api = getApi();
export { api as default }
export function changeApi() {
    api = getApi();
}

// somepage.js
import api, {changeApi} from 'apicontainer'
changeApi();
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
2

Yes, It is possible because ES6 modules export bindings (live connections). Read more here

apicontainer.js

import mockApi from './mock-api';
import realApi from './api';

function getApi() {
   return Cookies.get('isMock') ? mockApi: realApi;
}

export function changeApi() {
    api = getApi();
}
export let api = getApi();

somepage.js

import { api, changeApi }  from './path-to/apicontainer';
// whenever you change the condition (cookie in this case) 
changeApi(); // must call the `changeApi` to update the api reference value

Read more about how ES6 modules works

Carloluis
  • 4,205
  • 1
  • 20
  • 25
  • `export default api` is the one and only way where this does *not* work. – Bergi Mar 27 '18 at 23:01
  • @Bergi thanks to point that out. I just update the answer! Btw, I just checked you have the same issue in your code snippet – Carloluis Mar 28 '18 at 01:11
  • I think is equivalent with my old snippet intention. In fact, you also have an error in the export default syntax `export default let api = getApi()` because the *default export* is valid only with a *function* or *class* declaration or *expressions* (not allowing variable declarations). I think the downvote is unnecessary in my answer. Cheers – Carloluis Mar 28 '18 at 02:09
  • Oops, how could I forget [that](https://stackoverflow.com/questions/36261225/why-is-export-default-const-invalid). But no, I didn't have that intention, I specifically did not use `export default` with an expression - which is the only case where one exports a value, not a live connection (under the hood, a live connection to an invisible constant that gets initialised with the value). Thanks for the edit, I removed my downvote. – Bergi Mar 28 '18 at 02:17
0

Yes, mutable exports can be used (abused) in that way - if an export gets reassigned in the original module, it'll be reassigned wherever it's imported, but it's not really recommended. It would be better to have the modules consuming the API to do the proper test to identify which API (the mock or the real) to use, and to import said API directly from the source. You don't really want a variable one module is using to get silently reassigned (from that module's perspective) - it's unclear.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320