2

I'm fetching some data from firebase and would like to run async/await function (to fetch data) only once upon the first page load. I'm used to React and lifecycle methods / hooks doing it but this little project is just too small to use React. I just need to run this function once, fetch the data, save it to a variable and do not make any further calls to firebase api in the same session.

async function getEntries() {
  const snapshot = await firebase.firestore().collection('riders').get()
  // Do my thing with the data, etc.
  // console.log(snapshot.docs.map(doc => doc.data()));
}

Is there any js-only way of running this function only once when the page loads?

Wasteland
  • 4,889
  • 14
  • 45
  • 91

5 Answers5

1

Yes. You can use Self Invoking (self executing) Functions. Syntax is like:

(function(){})();

The last parentheses are for running function. the function is anonymous.

You can Implement it this way:

(async function () {
    const snapshot = await firebase.firestore().collection('riders').get()
})();

in this way you can never call this function again and it will run only once.

Tutorial: https://blog.mgechev.com/2012/08/29/self-invoking-functions-in-javascript-or-immediately-invoked-function-expression/

And The question you asked is somehow duplicate and answered here: Function in JavaScript that can be called only once

Re9iNee
  • 412
  • 5
  • 15
1

If you call a function just once, why do you need the function at all?

const snapshot = await firebase.firestore().collection('riders').get()
// Do my thing with the data, etc.
// console.log(snapshot.docs.map(doc => doc.data()));

This top level await only works in modules, and it blocks all depending modules to load. If that is not necessary (they don't depend on the data), or if you don't want write a module, you can wrap the code in an async IIFE, and store the returned promise in a variable:

 const dataPromise =  (async function() {
   //...
   return data;
 })();

While the data is loading, you might want to show some loading icon or so. That can easily be done with the following hook:

 function usePromise(p) {
   const [state, setState] = useState(null);
   useEffect(() => { p.then(setState); }, []);
   return state;
 }

// Inside a component:
const data = usePromise(dataPromise);
if(data === null)
  return <Loading />;

// show data
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
1

I think you can load it with the load method when the page is first loaded and then set it to cookie or local stroge. You can check this value on next page loads. You can do this quickly using jQuery.

$(window).load(function() {

     var item = localStorage.getItem('test');
     if(item != null){
      // your code
     }
     else {
      localStorage.setItem('test', 1);
     }         
});
1

What you are looking for is memoization of the function result. There are several libraries to supporting including react.

Theres also a handmade pattern you can use by changing the function implementation after it's called once, accoring to JavaScript: The Good Parts

async function getEntries() {
  const snapshot = await firebase.firestore().collection('riders').get()
  // Do my thing with the data, etc.
  // console.log(snapshot.docs.map(doc => doc.data()));
  
  getEntries = async function(){
     return snapshot
  }

  return snapshot
}

uke
  • 893
  • 4
  • 10
1

The simplest way is to make a global variable like:

let isCalled = false;

and in the function body do:

if(isCalled) return;
//the stuff the function would do
isCalled = true;
//Assign isCalled to true before using a return statement as it will make the program discard the lines below it.
faBri_CI-o
  • 53
  • 1
  • 6