asyncData or fetch method with Parameters in NuxtJs - vue.js

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
}

Related

How to render a page content with dynamic routing on page reload?

I have a SPA with dynamic routing. On page loading I'm making a fetch request for products. Then set it to the vuex store and use it. I also have a dynamic routing for product pages '/product/:id'
The problem is if I reload a product page say site.com/product/2 then nothing renders. I think this happens because at that moment store is empty and there're nothing to render.
How can I fix that?
In ProductPage component I tried using navigation guard with no success. Code below returns error: Cannot read properties of undefined (reading 'products').
Fetch request is made on mounting in TheMain component (when I reload ProductPage fetch request is made as well).
ProductPage component:
computed: {
...mapState(["products"]), // get products array from store
},
beforeRouteEnter(to, from, next) {
if (this.products) { // check if products array exists and then load data
next(true);
}
},
I think you need to make beforeRouteEnter async and add await for the store action which does the fetch or axios call.
async beforeRouteEnter(to, from, next) {
if (this.products) {
// check if products array exists and then load data
await dispatch(‘action_to_get_data’);
/// Wait to go to next for dispatch to finish.
next(true);
}
}
In your action you also need to use async / await.
What also might help is a v-if on the ProductPage component, so the components only loads when the products are loaded in the store.
For vue3 you may also take a look at the experimental Suspense component. But I don’t know if this works with beforeRouteEnter.
Hope this helps.

Access data from dispatched action using Vuex 4 and Vue 3 Composition API

In my application I have a Vuex 4 store and a Vue 3 Composition Api setup() method.
In the stores action I use axios to make an api call to get a list of bill payments.
The getAllBills action does not live directly in my Store.js file, it exists as a module.
getAllBills({ commit }) {
BillApiCalls.getBills().then(res => {
commit('GET_ALL_BILLS', res.data)
}).catch(error => console.log(error))
},
Then in my Bill.vue file I have the setup() method and am trying to access the data to be used throughout the same Bill.vue file.
setup () {
//Vuex store
const store = useStore();
const billPayments = store.dispatch('payment/getAllBills').then(res => console.log(res));
}
If I check the console from the above .then() res returns as undefined. If I remove the .then() from the billPayments declaration and just do:
console.log(billPayments)
In the console I get
Promise {<pending>}.
Current Store:
import { bill } from './modules/bill.module';
const store = createStore({
modules: {
bill
}
});
The endpoint is working, if I use Postman all of my data is returned as expected but I am having trouble figuring out how to access that data using a dispatched action with the composition api.
The Vuex 4 docs don't mention how to actually resolve the promise to access the data to be used throughout the same component.
An action isn't generally supposed to return data it acts on, data is a part of the state and should be accessed there; this is what another answer shows:
await store.dispatch('payment/getAllBills')
console.log(store.state.payment.bills);
The action doesn't chain promises so it cannot be correctly used. It should be:
return BillApiCalls.getBills()...
Or prefer async..await together with promise to avoid some common mistakes that can be made with raw promises.

Load async data into the vuex store when Nuxt app loads

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
...

Share code in asyncData and mounted using Nuxt

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.

Issue using redux variables via redux call inside react-apollo graphql with apollo compose

My Component needs to call an graphql query but it needs variables which can be only used by redux. So I have mapped the redux's connect to react apollo compose. But I have issues getting the data from reducer and the call is not loading properly.
class abc extends Component {
componentWillMount() {
console.log(this.props.variableData); // Getting empty object.
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ variableDataFetchAction }, dispatch);
}
function mapStateToProps(state) {
return {
variableData: state.reducerName.variableData,
}
}
export default compose(
connect(mapStateToProps, mapDispatchToProps),
graphql(MyQuery, {
options: props => {
return {
.....,
variables: props.variableData,
};
},
}),
)(abc);
I need to know whether there is problem in the way in which I can redux. Because my store seems to empty.
Just to be clear, you don't need react-apollo to call a GraphQL api endpoint.
In your case, you're utilizing 2 library that handle it's own store (assuming you're using Apollo Client 2). Redux has it's Redux Store and Apollo is using InMemoryCache for caching.
Stuff you fetched via graphql are stored in Apollo cache, you can use Apollo Client Developer Tools Chrome extensions to inspect it's content.
If you want to put the data fetch via apollo-client back to Redux store, you have to manually dispatch an action to do it (once the data return from graphql calls). This is mostly undocumented since it's not recommended to use 2 types of Store.
If all you need is to call a GraphQL endpoint and not changing your Redux implementation. I suggest using apollo-fetch or graphql-request instead.