Code Optimization in Vue.js—Refactoring a Phone Code Getter with JS localStorage

David Abiola
4 min readJun 27, 2021
Photo by Alexander Andrews on Unsplash

Although things within our codebase don’t always turn out the way we imagine they would, and (obviously) not all refactoring make for better performance, but sure, from time to time we all battle the tendency of becoming too wrapped up in our own over-engineering bubble — trying so hard to get our implementation perfect from the start. I have learned over time not to worry so much about getting it right from the start but instead, making small changes in incremental steps while prioritizing the bits with the most performance implication.

Let’s consider a scenario that can potentially require some urgency in the need to optimize our implementation:

To be able to send an OTP to a user via SMS, (assuming we already have their phone numbers), we need a way to automatically detect their phone code, depending on each user’s country of location, and so, we have written a simple piece of code to help us get each user’s phone code once they come on a certain form page. Consider the snippet below — the phone code getter.

// PhoneCode.vue component

NB: https://ipapi.co/country_calling_code/ is an open source API for getting phone codes

...<script>
import axios from 'axios';

export default {
mounted() {
this.getCode(); // get phone code when page loads
},
data() {
return {
code: '+234', // set a default code
}
},
methods: {
getCode() {
axios.get('https://ipapi.co/country_calling_code/')
.then(({data}) => {
this.code = data; // update the default
})
.catch(err => console.error(err))
;
}
}
}
</script>
...

What’s the issue here, you ask?

Well, I’m glad you asked! From the above implementation, getCode() method will the fired every single time the (same) user loads our form page. The implication may seem inconsequential considering we’re using a free API, but consider a case where even a free API is metered or another case in which the API is pay per request? You may end up unintentionally racking up a huge bill, depending on how much traffic your app handles.

Since a user’s location isn’t very likely to change, we can fetch the data once, and have it stashed away in the browser, to be used anytime, as many times as needed. This drastically reduces the number of requests that’ll need to be potentially made to the API server for the retrieval of the exact same piece of data.

localStorage — Quick Overview

The localStorage read-only property of the window interface allows you to access a Storage object for the Document's origin; the stored data is saved across browser sessions.

localStorage is similar to sessionStorage, except that while localStorage data has no expiration time, sessionStorage data gets cleared when the page session ends — that is, when the page is closed. (localStorage data for a document loaded in a "private browsing" or "incognito" session is cleared when the last "private" tab is closed.)

— Source: MDN Web Docs. Read more here.

This handy property lets us save and retrieve data, on a window-by-window basis. It means you can store data in the browser scoped to a particular window/application. If you run an experiment in your browser’s dev tools console, to retrieve data you saved into a different app’s localStorage, it’ll simply return null.

A Refactor

Let us fetch a user’s phone code and store it using the aforementioned window object property. We can easily check for the availability of this data in the localStorage to determine whether or not there’s a need to make a request to the endpoint. See snippet below:

// Updated PhoneCode.vue component

...<script>
import axios from 'axios';

export default {
mounted() {
if (! localStorage.getItem('phoneCode')) {
this.getCode();
} else {
this.code = localStorage.getItem('phoneCode');
}
},
data() {
return {
code: '+234',
}
},
methods: {
getCode() {
axios.get('https://ipapi.co/country_calling_code/')
.then(({data}) => {
this.code = data; // update default
// store data as value with key phoneCode
localStorage.setItem('phoneCode', data);
})
.catch(err => console.error(err))
;
}
}
}
</script>
...

In the refactor above, getCode() method is now set up to conditionally run only when no value was found for a key of ‘phoneCode’ in the storage — localStorage.getItem(‘phoneCode’) returns null and evaluates to false. And every time a value is found, it is used to replace the default value of this.code, without a need to ever run the getCode() method.

Summarily, we can get a significant performance boost, and even potentially save money and other resources when we implement some form of data caching mechanism or the other, especially in handling cases where these data aren’t very likely to change at all, or not likely to change frequently.

Save some resources, save the world!

--

--

David Abiola

Human & software engineer. Interested in ()=> {[Arts, Education, Music, Science, Tech, AI, co-Humans]};