How to Use Global Variable among ES6 Modules
Adam C. |

ES6 Modules give us a lot of freedom, so then we can write functions in a different module. An ES6 module is a file containing JS code, and we can import and export it in modules. 

Photo by Kaleidico on Unsplash

Recently, I would like to accomplish a special task, which is passing a variable (being updated) from one module to another one. It's like a global variable,  and it should be straightforward if we have everything in one file, for example:

var globalTooltips = [];

function veryComplicatedProcess(data){
	//some complicated logic
	const newData = shapeMe(data)
	saveData(newData);
	// additional task
	const tooltips = getTooltips(newData.someField);
	globalTooltips.concat(tooltips);
}

function exportAll (rawData) {
	rawData.forEach(data => {
		veryComplicatedProcess(data);
	});
}

function process() {
	const rawData = somethingOtherFunction();
	exportAll(rawData);
	// save tooltips
	saveTooltips(globalTooltips);
}
process();

As you see,  the goal is to add an additional task (saveTooltips) to the existing process. Note that the getTooltips can be done during the existing data processing, but it's hard to get from the existing result. So it's ideal to save the tooltips using the global variable and then save them after the existing process is done.

However,  the actual logic is much more complicated than this, and we use ES6 Modules, which means verComplicatedProcess() is in a different module.  The challenge here is how to pass the global variable from one module to another module. 

The first thing I thought of is using Closure,  which allows the inner function to access the outer function. But in order to use Closure, we have to nest the functions inside the main function, which is process(), in my case. Something like,

function process() {
	let globalTooltips = [];
	const rawData = somethingOtherFunction();
	function exportAll (rawData) {
		rawData.forEach(data => {
			function veryComplicatedProcess(data){
				//some complicated logic
				const newData = shapeMe(data)
				saveData(newData);
				// additional task
				const tooltips = getTooltips(newData.someField);
				globalTooltips.concat(tooltips);
			}
		});
	}
	// save tooltips
	saveTooltips(globalTooltips);
}

But this is not practical in my case, because the inner function is way more complicated than the demo code above.

The good news is we could use a Context module to resolve this issue easily in ES6 Modules.

First, I created a Context module named globalContext.js, like:

const globalContext = {
  tooltips: [],
};
export default globalContext;

Then in the main.js, I imported it as:

import globalContext from "./globalContext";
import veryComplicatedProcess from "./veryComplicatedProcess.js";

function exportAll (rawData) {
	rawData.forEach(data => {
		veryComplicatedProcess(data);
	});
}

function process() {
	const rawData = somethingOtherFunction();
	exportAll(rawData);
	// save tooltips
	saveTooltips(globalContext.tooltips);
}
process();

Also, imported  globalContext in another module containing veryComplicatedProcess function, like:

import globalContext from "./globalContext";

export default function veryComplicatedProcess(data){
	//some complicated logic
	const newData = shapeMe(data)
	saveData(newData);
	// additional task
	const tooltips = getTooltips(newData.someField);
	globalContext.tooltips.concat(tooltips);
}