I want to share same code block to get data in asyncData and mounted using Nuxt.
For example in asyncData
async asyncData({ $api, $auth, route, error, store }) {
if( !process.server ) return null;
let res = {};
let stockData = await $api.stocks.getStock(route.params.name);
if( stockData ) { res.stockData = stockData.data; }
return res;
},
And in mounted()
if(ObjectHelper().isEmpty( this.stockData )) {
this.$api.stocks.getStock(route.params.name).then(res => {
this.stockData = res.data;
})
}
Those two code blocks are all getting data from server-side. How to write a common function to reuse it but not write twice? In nuxt documents, You do NOT have access of the component instance through this inside asyncData because it is called before initiating the component.
Regarding your comment to have the API call server and client-side, which is the reason for your question - it is not necessary to duplicate or share it within mounted as asyncDatagets called server and client-side. You will find following in the nuxt docs:
asyncData is called every time before loading the page component. It
will be called server-side once (on the first request to the Nuxt app)
and client-side when navigating to further routes.
That means - lets say you have your asyncData on page A and a user enters your site using page B and navigates client-side via a nuxt-link from page B to page A it will fire asyncData client-side too before initializing the page component.
Related
I'm working on a nuxtjs project, using asyncData and fetch methods but I need to use parameterize url for get requests and the parameters are present in the data property of vue. How will I use it.
....
data(){
return {
param1: "455",
param2: "xyz",
products: []
}
},
asyncData(){
return axio.get(`/api/products?type=${param1}&cat{param2}`).then(response => {
this products = response.data
})
}
The approach I used here for parameterize url is correct? Please also discuss for fetch methods as well
You can't. asyncData hook runs before creating the component, so it doesn't have access to the component instance (because it doesn't exists yet).
asyncData could have access to global properties throught the Nuxt context, such as:
route parameters
vuex store
injected properties with plugins
You could use the fetch hook instead, which does have access to this (the component instance).
The difference is that it won't block the page render on client navigation, so you have to handle the loading state with $fetchState.pending.
fetch () {
return axio.get(`/api/products?type=${this.param1}&cat{this.param2}`).then(response => {
this products = response.data
}
I have a Vue app which does a little localStorage and server check on app load, to determine where to initially route the user.
This is in the App's main entry component, in the created() hook
My problem is that the default / route's Component visibly loads first, then the server call and everything happens which causes the user the route to their correct location
How can I delay the rendering of the initial component until my app's main component created() method completes, and then purposely navigates the user to the correct route?
I had this problem before and I firmly believe that you must have the initial files for your routes and your router configuration.
In the configuration, you could handle the permission and router before each route and with next() . In the router file, you can set your params and check them in the index.js file(router configuration)
you could also use your localStorage data in Router.beforeeach
EDIT: I just saw you used the created method... like mentioned below use beforeRouteEnter instead with the next() parameter it provides
First of all I wouldn't recommend using a delay but instead a variable that keeps track if the API call is done or not. You can achieve this using the mounted method:
data() {
return {
loaded: false,
}
}
async mounted() {
await yourAPICALL()
if (checkIfTokenIsOkay) {
return this.loaded = true;
}
// do something here when token is false
}
Now in your html only show it when loaded it true:
<div v-if="loaded">
// html
</div>
An better approuch is using the beforeRouteEnter method which allows you to not even load the page instead of not showing it: https://router.vuejs.org/guide/advanced/navigation-guards.html
I have Nuxt Vue 2 app. There is a redirect in the mounted hook to the same route. The only difference in this route is query string. It looks like
mounted() {
...
if( !isTokenOwner ) {
const result = await this.$api.campaignNewShare.copyNewShare(this.newShareToken);
localStorage.setItem(result.data.token, new Date().getTime());
this.$router.replace({'name': 'campaigns-new', 'query': {token: result.data.token}});
this.loading = false;
return;
}
}
It seems that Vue stays on the same page and only replace the url query string parameter. But I need to redirect to the new location with whole new lifecycle.
Can somebody tell me what really happened there after the replace() call? Why it does not trigger the real redirect? Thnaks.
Ok so as documentation says
One thing to note when using routes with params is that when the user
navigates from /user/foo to /user/bar, the same component instance
will be reused. Since both routes render the same component, this is
more efficient than destroying the old instance and then creating a
new one. However, this also means that the lifecycle hooks of the
component will not be called.
We have a nuxt.js application which retrieves data from strapi. this works for all the other pages that we've created, but when we try to retrieve data for the <Footer /> it appears that the code is not executing.
This is the code that we use for retrieving on the index page:
export default {
async asyncData({ $strapi }) {
return {
homepage: await $strapi.find("homepage"),
};
},
}
All we change from page to page is the variable name and the value its finding.
This works on 10 - 12 pages.
On main pages we are able to retrieve the data of the footer with this code:
export default {
async asyncData({ $strapi }) {
return {
footer: await $strapi.find("footer")
};
},
}
However when we put this code in our footer component it doesn't appear to execute, as no variable was shown in the view explorer, and if we try an render anything form the {{footer}} then we get an error saying we've referenced something that doesn't exist.
Is there any reason why this code isn't executing in the footer component?
The asyncData hook can only be used on page components. The official documentation explains how you can work around this issue:
asyncData is only available for pages and you don't have access to this inside the hook.
Use the new fetch hook that is available in Nuxt 2.12 and later versions.
Make the API call in the mounted hook and set data properties when loaded. Downside: Won't work for server side rendering.
Make the API call in the asyncData method of the page component and pass the data as props to the sub components. Server rendering will work fine. Downside: the asyncData of the page might be less readable because it's loading the data for other components.
I am trialling a project in Nuxt. Liking it so far except I am a little confused as to how to load data from an external async service so that it is available in Vuex from the very first route.
I have tried adding middleware on the default layout to dispatch the store action but I do not see the service being called straight away. Only when I navigate deeper into the routes do I see the action dispatched.
I did something similar in a standard Vue project and added the created method to the App.vue.
Is there a similar way in Nuxt?
What you need is called a fetch.
The fetch method, if set, is called every time before loading the component (only for page components). It will be called server-side once (on the first request to the Nuxt app) and client-side when navigating to further routes.
Warning: You don't have access of the component instance through this inside fetch because it is called before initiating the component.
async fetch({ store }) {
await store.dispatch('your-action')
}
If you need parameter:
async fetch({ store, params }) {
await store.dispatch('your-action', params.id)
}
I gave an example of id. The name of the parameter depends on the name of your page.
_id => params.id
_slug => parmas.slug
...