Is it possible to use nuxt fetch() and set the values in head()? - vue.js

The problem is that head() seems to be executed before async fetch(), which causes errors when trying to insert page's metadata and title. I KNOW asyncData exists, but the fact that it blocks page loading at a route transition level makes it provide such a HORRIBLE user experience (in a mobile device with bad connection, page transition can stay blocked for seconds) and reminds of old PHP rendered websites, not a modern SPA. Nuxt fetch() in the other hand, while still server side rendering the page, exposes $fetchState.pending and makes possible to exhibit an instant page transition showing the page skeleton, for example (consequently making the user experience better). The only problem i am having is this one with head() data. Is this problem solvable or just one unsolvable drawback of using fetch() instead of asyncData()?
Important Note: I am referring to Nuxt's new fetch method, not the legacy one.
example code that doesn't work:
data() {
return {
car: null,
}
},
async fetch() {
this.car = await this.$axios.$get('/cars/' + this.$route.params.id)
},
head() {
return {
title: this.car.name,
}
},

My colleague did a talk a few weeks ago, speaking about SEO in general, here is related section: https://youtu.be/W9camkXNjkw?t=920
Looking at all my given answers regarding SEO and also Github issues, all examples are using asyncData or some static approach.
When you think about it, I'm not sure how you could generate something on SSR, while being totally dynamic + non-blocking.
Either you know it ahead of time and can generate the OG tags, or you don't if it's totally volatile.

Related

Using Vue Composition API with Pinia

I have a Vue 3 project and I'm working with Composition API. I'm communicating with my backend using Urql which is a graphql library which allows me to wrap API requests as composables.
I'm new to Pinia, but after a bit of time working with Vue 2 + Vuex I can tell that one of the most common scenarios of writing actions was making API requests and updating the state (asynchronously) with the response. I'm trying to adopt the same technique in my current tech stack and facing some issues.
My problem is that I can't just use the old fashioned fetch/axios/got libraries to execute requests whenever I want, I should first register the composable somewhere. I've seen that one option is to call the composable's use* function in the store's state section, but it seems weird to me to have such thing in there as it has nothing to do with the state. I've tried executing the use* method directly in an action, but it seems to fail.
I wonder if I'm missing some best-practice way to work with Urql and Pinia, as things are getting more and more complex even though my usecase is pretty common and simple. Should I use Urql's Client directly? Any other good solution to make gql requests from within my store actions?
export const useUsersStore = defineStore('app', {
actions: {
setUser() {
const response = (await useUsers()).data // this wont work
},
}
);

Fetch huge API response without blocking the rendering of the page in Nuxt?

I have a dynamic page in Nuxt where I use Fetch and Axios to get all the data I need like photos/text my problem is that the API is quite long (more than 3800 lines).
The page loads with nothing appearing during 11 seconds so I was wondering if it's possible to not wait the end of the fetch call and make appearing the first results while the other one continue loading.
I try chaining fetch call with no success. I hope someone could guide me for the solution.
Here is my fetch:
async fetch() {
let path = this.$nuxt.context.route.path
this.response = await axios.get(
`/api${path}`,
{
headers: {
'X-AUTH-TOKEN': process.env.SECURE_TOKEN,
'Content-Type': 'application/json'
}}
).then((res) => {
this.models = res.data.content;
})
},
fetchOnServer: true,
At the end, you will not need to fetch all of them.
Pagination is still the way to go because loading 3800 elements on a webpage is not the way to go if you're display only 10 or even 100 of them (will be too heavy to handle JS-wise and not useful anyhow).
There are ways to achieve that with some advanced patterns but still, totally not needed here.
What you should do is look for some pagination on the API. If it's not available, I still recommend that you do that ahead of time rather than on client-side.
Also, using some infinite-scroll is quite a good idea to paginate 10 elements on each iteration.
Some solutions on how to implement that are available in my previous answers.
Otherwise, here are some useful packages for that purpose.

Retrieve a file before anything else happens

Iʼm creating a simple SPA that will retrieve data from an API. The page itself is served by a separate backend process which is the only entity that knows the API address. As such, it also provides an endpoint that, among other things, returns the API URL:
{
"api_url_base": "http://api.example.org/v1"
}
This is needed because the whole thing is deployed at multiple sites where we donʼt have control over DNS records and it may or may not be easy to derive the API URL from the front end appʼs.
Now i need to write my Vue app so nothing can happen until i fetch and process this file. To achieve that, i added to the appʼs beforeMount method:
this.settings = axios.get('/settings.json');
and in my componentsʼ beforeMount:
var comp = this;
app.__vue__.settings.then((response) => {comp.url = response.data.api_url;});
However,it seems the componentʼs beforeMounted often runs before the appʼs, and app. __vue__.settings is undefined when i get to the componentʼs beforeMount.
Where do i go wrong? Am I putting things at wrong places, or is my approach completely wrong?
You can fetch data before mount the vue app.
axios.get('/settings.json').then(response => {
// do something with response
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
}
One way (as suggested in the previous answer) is to make one more call, before anything else. However it brings numerous downsides.
Let me just say that it freezes the loading of your application until the response is received.
There is hope as you can cleverly use (f.e.) good ol' dependency injection to pass the required data to your app.
This article answers this question fully and completely: https://codeburst.io/passing-configuration-to-vue-js-1b96fa8f959

"Default Apollo Queries" VS "AsyncData" (Nuxt.js)

I'm building a site with Nuxt/Vue, and it's using a GraphQL backend API. We access this using the Apollo module for Nuxt.
In a page component, you can do this (I think this is called a Smart Query, but I'm not sure):
apollo: {
pages: {
query: pagesQuery,
update(data) {
return _get(data, "pageBy", {});
}
},
}
}
But you can also do the query like this I think, using the Nuxt asyncData hook:
asyncData(context) {
let client = context.app.apolloProvider.defaultClient;
client.query({query, variables})
.then(({ data }) => {
// do what you want with data
});
}
}
I'm not sure what the difference is between these two ways, and which is better. Does anyone know? I couldn't find an explanation in the docs anywhere.
Yeah, good question. The code you have shown at the top is indeed called a Smart Query. In fact
Each query declared in the apollo definition (that is, which doesn't
start with a $ char) in a component results in the creation of a smart
query object.
A nuxt project using the #nuxtjs/apollo module can use these out of the box. The beauty of the smart query is the options that it comes with and one of these is the 'prefetch' option. This, as it sounds, allows prefetching and is by default set to true. It can also accept a variables object or a function. You can see the docs here.
This means that the outcome of a smart query or an asyncData query will essentially be the same. They should be resolved in the same timeframe.
So why choose one or the other? This would probably be down to preference, but with all the options that a smart query allows you can do a lot more, and you can include subscriptions which might not be possible in asyncData.
More about smart queries here.

Flux without data caching?

Almost all examples of flux involve data cache on the client side however I don't think I would be able to do this for a lot of my application.
In the system I am thinking about using React/Flux, a single user can have 100's of thousands of the main piece of data we store (and 1 record probably has at least 75 data properties). Caching this much data on the client side seems like a bad idea and probably makes things more complex.
If I were not using Flux, I would just have a ORM like system that can talk to a REST API in which case a request like userRepository.getById(123) would always hit the API regardless if I requested that data in the last page. My idea is to just have the store have these methods.
Does Flux consider it bad that if I were to make request for data, that it always hit the API and never pulls data from a local cache instance? Can I use Flux in a way were a majority of the data retrieval requests are always going to hit an API?
The closest you can sanely get to no caching is to reset any store state to null or [] when an action requesting new data comes in. If you do this you must emit a change event, or else you invite race conditions.
As an alternative to flux, you can simply use promises and a simple mixin with an api to modify state. For example, with bluebird:
var promiseStateMixin = {
thenSetState: function(updates, initialUpdates){
// promisify setState
var setState = this.setState.bind(this);
var setStateP = function(changes){
return new Promise(function(resolve){
setState(changes, resolve);
});
};
// if we have initial updates, apply them and ensure the state change happens
return Promise.resolve(initialUpdates ? setStateP(initialUpdates) : null)
// wait for our main updates to resolve
.then(Promise.params(updates))
// apply our unwrapped updates
.then(function(updates){
return setStateP(updates);
}).bind(this);
}
};
And in your components:
handleRefreshClick: function(){
this.thenSetState(
// users is Promise<User[]>
{users: Api.Users.getAll(), loading: false},
// we can't do our own setState due to unlikely race conditions
// instead we supply our own here, but don't worry, the
// getAll request is already running
// this argument is optional
{users: [], loading: true}
).catch(function(error){
// the rejection reason for our getUsers promise
// `this` is our component instance here
error.users
});
}
Of course this doesn't prevent you from using flux when/where it makes sense in your application. For example, react-router is used in many many react projects, and it uses flux internally. React and related libraries/patters are designed to only help where desired, and never control how you write each component.
I think the biggest advantage of using Flux in this situation is that the rest of your app doesn't have to care that data is never cached, or that you're using a specific ORM system. As far as your components are concerned, data lives in stores, and data can be changed via actions. Your actions or stores can choose to always go to the API for data or cache some parts locally, but you still win by encapsulating this magic.