"Default Apollo Queries" VS "AsyncData" (Nuxt.js) - vue.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.

Related

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

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.

Most efficient way to filter an API response

I'm building a stock market overview app in Vue (+Vuex), getting market data from an API, then being updated every x seconds over websocket
Now i want to have a little section that shows "best performing markets"
I'm wondering what would be the most efficient way to handle this calculation.
(all in pseudocode)
1
(in vue component)
computed: {
getTopMarkets() {
filterTopMarkets(this.$store.state.markets)
}
}
2
(in vuex getter)
getters: {
topMarkets() {
return filterTopMarkets(state.markets)
}
}
#3
(other possibilities i am missing?)
is there a difference to the two approaches above (calculate in a computed property vs. calculate in a vuex getter)? is one faster than the other? better than the other? why?
thanks! :)
Both Vuex getters and computed component properties are JavaScript getters.
The long syntax of a computed is:
computed: {
yourComputed: {
get: function() { return expression }
}
}
equivalent of:
computed: {
yourComputed() { return expression }
}
and you can always define setters for computed:
computed: {
yourComputed: {
get: function() { return expression },
set: function(value) {
// dispatch an action or commit a mutation using value
}
}
}
This, combined with Vue's reactivity (or change detection mechanism) means that once they're run once, every time they're requested again Vue will serve the previously computed value - that's why they're called computed - (without actually re-running the code) until the moment any of the dynamic bits (references) change. When references change, the getter (whether it's a Vuex getter or a computed property) is rerun and all places where its referenced are notified (and those are re-run/re-rendered, in turn).
The only difference between the two cases is: Vuex getters are cached at store level, computed props are cached at component level.
In terms of both performance and change detection they're basically the same (internally they use the same mechanism).
Now, if you're only using this in one single component, the recommendation is not to use Vuex, as you'll have unnecessary additional boilerplate code around your data.
You're better off using a private store inside your component (either Vue.observable() or a Vue instance - before Vue.observable() was a thing, that was the way to create a basic Store without all the bells and whistles a Vuex store comes with).
Note: The mentioned alternatives allow you to expose the component's private store. If you don't need to expose it, don't bother: each component already has a private store: the data function (exposed to template). All you need to do is declare the reactive props upfront and from that point on the component will react to applied changes.
As already stated in the comment below your question, the choice here should not be based on code performance (as it's basically the same), but based on development and code management performance.
On how much your project will benefit from the order/structure Vuex comes with, in the long run:
how complex will your app get in time,
how many developers are/will be working on it and how well defined are the project's private conventions (if any)
how decoupled do you want/need data management and components to be)
how many iterations of this app are you expecting/foreseeing?
The more complex the project (codebase size, data structure complexity, app logic complexity, number of app iterations, number of developers), the more benefit you'll get from using Vuex, IMHO.

Prefetching API Data with Apollo for Nuxt.js SSR

I've got what is hopefully a very simple question about prefetching data from within an apollo/nuxt configuration.
I am requesting data from a GraphQL API and want to prefetch the data to use server-side rendering. Reading the docs it seems like I should simply be able to set prefetch: true on my apollo query but this is not working – it is always sending the request from the client side which is causing all kinds of issues.
Here is the code in my component:
apollo: {
concept: {
prefetch: true,
query: conceptStatements,
variables () {
return { id: this.$route.params.id }
}
}
}
I feel like it will have something to do with when this.$route.params.id is evaluated?
Ultimately I would like to create a Vuex store in the store/index.js which takes all of my apollo queries and renders the data in them accessible across the application but the documentation is very vague on how I might do this. Any help would be much appreciated!
Are you really sure your data is not prefetched?
Prefetch is for the first rendering (in SSR mode) ; Nuxt/Apollo call your graphql api, generate the page and send it to the browser. If you just navigate to your page from another route, nuxt call your api from the browser.
You can check this behavior in devtools/network, select xhr. Refresh your page, there is not xhr call. Go to another route and refresh your page, then navigate to your route where is your apollo query and you should see a xhr call to your graphql api.
Also, you can configure this behavior in your apollo config with fetchPolicy.
You don't need Vuex to store response of your apollo queries:
From vue-apollo doc:
When you perform GraphQL queries with Apollo, the results of API calls
will be stored in Apollo cache. Now imagine you also need to store
some kind of a local application state and make it available for
different components. Usually, in Vue application we can achieve this
with Vuex. But having both Apollo and Vuex will mean you store your
data in two different places so you have two sources of truth.
So, if your perform same query from different page or component, Apollo don't call your api each time, but retrieve data from the Apollo cache. Apollo is just magic!

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

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.