Leveraging VueJS 2.0 server-side rendering: Maximizing data retrieval efficiency with preFetch and beforeRouteEnter techniques

Exploring VueJS server-side rendering and troubleshooting some issues. Using the latest VueJS Hackernews 2.0 as a starting point for this project.

Currently facing an obstacle:

The server fetches data using the preFetch method. All seems well. When a user navigates to this component, the same function is called within the beforeRouteEnter function. Everything looks good.

However, on the initial page load, the preFetchData function is executed twice - once in preFetch and once in beforeRouteEnter.

This behavior is expected due to the way Vue Router operates. The server runs preFetch, and when Vue renders on the client side, beforeRouteEnter is triggered.

Yet, I don't want Vue to fetch the data twice during the first load since it's already in the store from the server-side rendering via preFetch.

I can't check if the data is in the store because I need that component to always make the API call on beforeRouteEnter, except for the initial render coming from the server.

Any suggestions on how to retrieve the data only once in this scenario?

  <template>
    <div class="test">
        <h1>Test</h1>
      <div v-for="item in items">
        {{ item.title }}
      </div>
    </div>
  </template>

  <script>
  import store from '../store'

  function preFetchData (store) {
    return store.dispatch('GET_ITEMS')
  }

  export default {
    beforeRouteEnter (to, from, next) {
      // Only execute this on the client side, not on the server
      // On the server, we have preFetch
      if (process.env.VUE_ENV === 'client') {
        console.log('beforeRouterEnter, only on client')
        preFetchData(store)
        next()
      } else {
        // Server side, just pass it
        next()
      }
    },
    name: 'test',
    computed: {
      items () {
        return this.$store.state.items
      }
    },
    preFetch: preFetchData // Only on server
  }
  </script>

  <style lang="scss">
  .test {
    background: #ccc;
    padding: 40px;

    div {
      border-bottom: 1px red solid;
    }
  }
  </style>

In the snippet above: the API call is made through store.dispatch('GET_ITEMS')

Answer №1

After some investigation, I have come to a solution. By checking the user's origin with from.name, we can determine if they are visiting the page for the first time since all my routes have names assigned. If it returns null, then we can infer that we are serving the server rendered HTML:

beforeRouteEnter (to, from, next) { 
    if (from.name && process.env.VUE_ENV === 'client') {
      preFetchData(store).then(data => {
        next(vm => {
          // do something
        })
      })
    } else {
      next()
    }
  }

Answer №2

Check whether you are currently on the server or not using Vue.

this.$isServer

or

Vue.prototype.$isServer

Ensure that your prefetch function is only triggered when you are on a local environment.

beforeRouteEnter(to, from, next) {
    // This function should only run client-side, not server-side
    // Use preFetch on the server
    if (!this.$isServer) {
        console.log('beforeRouterEnter, only on client')
        preFetchData(store)
        next()
    } else {
        // Server-side operation, proceed as usual
        next()
    }
},

Answer №3

One potential solution is to create a variable in the store indicating whether the data for the current page has already been loaded. By checking this variable, you can determine if an ajax request needs to be made.

Answer №4

Verifying the existence of the window object within the created method of this component:

created () {
  if (typeof window === 'undefined') {
    // This code is running on the server side
  } else {
    // This code is running on the client side
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to trigger an onclick event for an input element with a type of "image"?

In the code I'm working on, there's an input of type "Image". <div class="icon" id="button_dictionary"> <form> <input class="buttonDictionary" type="image" src="icone_dicionario.jpg" value="" id="inputDictionary"> ...

Issue with Transition-group functionality

Check out this CodePen link for reference. Despite setting up a transition-group, I am not experiencing the expected fade effect when clicking on the 'CONSTRUCTION PROGRESS' tab. <transition-group name="fade" class="row no-gutters" v-show=" ...

Adjust the element colors within a Vue loop with dynamic changes

Hey there! I'm currently working on achieving a unique design inspiration that involves colorful badges grouped together. Here's a visual reference: In the image, you can see these badges grouped in pairs, but they can actually be in sets of 4 o ...

List of images using React Native's FlatList

Seeking assistance with integrating images into a flatlist grid. I have successfully implemented text but struggling with images stored in the assets folder. The goal is to display separate images from the assets folder within the boxes of the flatlist gr ...

The error callback for Ajax is triggered even though the JSON response is valid

Within my JavaScript file, I am making the following call: $.ajax({ type: "POST", dataType: "application/json", url: "php/parseFunctions.php", data: {data:queryObj}, success: function(response) { ...

Merging object keys and values from JSON arrays based on their keys, using JavaScript

Is there a way to merge object keys' values from JSON arrays based on their key? json1 = [ {key:'xyz', value:['a','b']}, {key:'pqrs', value:['x','y']} ] json2 = ...

Using `useState` within a `while` loop can result in

I'm working on creating a Blackjack game using React. In the game, a bot starts with 2 cards. When the user stands and the bot's card value is less than 17, it should draw an additional card. However, this leads to an infinite loop in my code: ...

Utilizing Object-Oriented Programming in jQuery/JavaScript to effectively pass a value out of a function that is compatible across different browsers

While this question may have been asked before, I urgently need a solution for a production environment. I am feeling quite overwhelmed trying to figure out which objects I should create and utilize. function scroll(min, max) { // perform actions } fun ...

Ways to showcase a JSON menu with a single level

I have a json file containing links to all the images in a specific folder, as shown below: ["http://img1.png","http://img2.png","http://img3.png","http://img4.png"] I would like to create a <ul> list using this data, but I'm not sure how to d ...

The email provided is invalid according to the response received from the Campaign Monitor API within a Meteor JS

I'm currently facing an issue with a project using Meteor. I'm attempting to add an email address to a subscriber list through the Campaign Monitor API. To do this, I'm utilizing a npm package called createsend-node, which acts as a wrapper ...

Having trouble updating the input value in AngularJS?

As I venture into customizing an AngularJS tutorial on a Saturn Quiz, I am transforming it from multiple choice to a fill-in-the-blank quiz. The challenge I face is that the first answer registers as correct or incorrect, but subsequent questions always s ...

Efficiently bundling Angular templates using Grunt and Browserify

I am currently utilizing angular1 in conjunction with browserify and grunt to construct my application. At present, browserify only bundles the controllers and retrieves the templates using ng-include through a separate ajax call. Due to the excessive amo ...

What is the recommended placement for the implicitlyWait method in Protractor?

When implementing implicitlyWait, what is the appropriate location to include browser.manage().timeouts().implicitlyWait(5000); within the test script? ...

Ways to retrieve a list of identifiers from arrays at both initial and subsequent levels

I'm currently dealing with a JSON/JavaScript structure that looks like this: { "comments": [ { "id": 1, "content": "lorem ipsum", "answers": [] }, { "id" ...

What is the best way to create a full bleed background image that adjusts to different screen resolutions using CSS and JavaScript?

Similar Question: Full Screen Background Image in Firefox Check out: Is there a way to achieve a similar effect on a website where the content adjusts to different monitor resolutions? On the Ingress site, it seems like everything scales proportional ...

Updating the value of a v-text-field in Vuetify

What is the best way to modify input values? Here is an example: `https://jsfiddle.net/mbqjp4ax/` If a number entered is greater than 5, the system should automatically input the number 9 instead. While this works correctly when entering numbers greater ...

Trying to replace all instances of a word in an HTML document with a <span> element, but only for <p>, <span>, and <div> tags. It shouldn't work if the parent node already contains

Here is the HTML code snippet I am working with: <div> hello world <p> the world is round <img src="domain.com/world.jpg"> </p> </div> I am looking to replace the word "world" (or any mixed case variations) with < ...

Adding dots between page numbers when using ReactJS/Javascript Pagination can be achieved by implementing a specific method

I have created a pagination component using React JS. Currently, it only displays all the page numbers, but I want it to show dots when there are more than 8 total pages. Here's how I envision it: c. When total is less than 9 pages: Page 1 selecte ...

Error: Required variable missing in AJAX Post request

When making an ajax call, I use the following code: o.open("POST",q,true); o.setRequestHeader("Content-type","application/x-www-form-urlencoded"); o.setRequestHeader("Content-length",p.length); o.setRequestHeader("Connection","close"); Here, q represent ...

AngularJS views malfunctioning following oauth redirect

I am in the process of creating a web application using AngularJS and Firebase. Recently, I added a second page along with an ng-view to my index file. In order to facilitate login via Facebook or Google, I am utilizing the $firebaseAuth service. However, ...