Nuxt: How to access store in rollbar.js WITHOUT using localStorage? - vue.js

I am using Nuxt and Rollbar. I have a user id state in store.
My question is, how can I set this user id as a custom payload in the transformer function in rollbar.js WITHOUT using localStorage?
Here is my code:
// plugins/rollbar.js
const transformer = function(payload) {
payload.user_id = user_id_from_store // how to get this from store?
}
// store/index.js
export const state = () => ({
userId: ''
})
export const mutations = {
setUserId(state, userId) {
state.userId = userId
}
}
//components/MyComponent.vue
methods: {
fetch() {
const userId = fetchUserId()
this.$store.commit('setUserId', userId)
}
}
Things I have tried:
In rollbar.js, create and export a function which takes a context object as argument. Then call this function in transformer function to get user_id:
// plugins/rollbar.js
const getUserId = context => {
const user_id = context.store.state.userId
return user_id
}
const transformer = function(payload) {
payload.user_id = getUserId()
}
export default getUserId
When I console.log(context.store)in getUserId function, I got a Store object, but calling the function in transformer function threw Rollbar: Error while calling custom transform() function. Removing custom transform(). TypeError: Cannot read property 'store' of undefined.

At the end, OP succeeded thanks to inject, more info available here: https://nuxtjs.org/docs/2.x/directory-structure/plugins#inject-in-root--context
This one is indeed needed for libraries that are not directly into the Vue ecosystem but that we wish to have working in our Nuxt app.

Related

Vue 3 / Pinia: how to get the updated value from the store when it's changed?

Using Vue 3 with Pinia in an Interia setup. I can see Pinia in my Dev Tools and I can console log out the (starting) value.
I have a component set up like:
<Comment>
<ChildComment>
In ChildComment, I have this function
const toggleEdit = () => {
commentStore.childEditing = !editMode.value
editMode.value = !editMode.value;
};
When I trigger this function, the value updates in the store:
In the <Comment> component, I have tried using various methods like so:
import { useStore } from "../../store/commentStore";
const commentStore = useStore();
// USING STATE DIRECTLY
// const isEditingChildComment = ref(commentStore.childEditing);
// const isEditingChildComment = reactive(commentStore.childEditing);
// const isEditingChildComment = computed(() => commentStore.childEditing);
// USING GETTER
// const isEditingChildComment = ref(commentStore.getChildEditing);
// const isEditingChildComment = reactive(commentStore.getChildEditing);
// const isEditingChildComment = computed(() => commentStore.getChildEditing);
But isEditingChildComment is never updated in any of the above 6 scenarios, it remains as false:
Am I missing something obvious?
If you use a computed property, you need to return a value. For example:
const isEditingChildComment = computed(() => {
return commentStore.childEditing);
}
It looks also if you are mutating the store state directly. I think you should use an Action for that, to guarantee the working of reactivity.
Try using the store.$subscribe function. Here's a link to the docs
Example from docs:
cartStore.$subscribe((mutation, state) => {
// import { MutationType } from 'pinia'
mutation.type // 'direct' | 'patch object' | 'patch function'
// same as cartStore.$id
mutation.storeId // 'cart'
// only available with mutation.type === 'patch object'
mutation.payload // patch object passed to cartStore.$patch()
// persist the whole state to the local storage whenever it changes
localStorage.setItem('cart', JSON.stringify(state))
})

Vue JS composition API can't access array

I am currently trying to learn Vue JS without ever having encountered Javascript.
All the brackets, arrows, etc. are driving me crazy.
With the Composition API, I come across a question that I can't successfully google.
That's working:
setup() {
const store = useStore ();
const packagingdata = ref ([]);
const loadpackagingdata = async () => {
await store.dispatch (Actions.LOADPACKAGING_LIST, 10);
packagingdata.value = store.getters.getPackagingData;
return {
packagingdata,
}
I can access {{packagingdata}}. That contains an array.
{{Packagingdata.products}}
does work
but {{packagingdata.products [0]}} doesn't work.
But when I add it to the setup () like this:
setup() {
const store = useStore ();
const packagingdata = ref ([]);
const getProducts = ref ([]);
const loadpackagingdata = async () => {
await store.dispatch (Actions.LOADPACKAGING_LIST, 10);
packagingdata.value = store.getters.getPackagingData;
getProducts.value = store.getters.getProducts;
};
return {
packagingdata,
getProducts
}
then {{ getProducts }} returns what I wanted even if the getter function only is like this:
get getAddress() {
return this.packagingdata["products"][0];
}
What is happening there?
What am I doing wrong? I would prefer to not create a ref() and getterfunction for every computed value.
Whats the solution with computed?
best regards
I found two methods to avoid the error.
add a v-if="mygetter.length" in the template
check in the getter whether the variable is set and otherwise return false
Both of these prevent an error already occurring when the page is loaded that [0] cannot be found

Why is 'route.params.id' unavailable/undefined in setup method?

I'm working with vue-router and Vue 3. I have a view where I'd like to take the router url and use it to call a method to access an API. This method returns a promise I can use to populate my page. When calling my method with 'route.params.id', it says that the parameter is undefined. When I do console.log(route.params.id), it displays correctly in console. I've tried using a computed property instead, but I had the same issue.
Setup code:
import { ref } from "vue";
import MovieApiService from "../api/MovieApiService";
import { useRoute } from "vue-router";
export default {
setup() {
const movie = ref([]);
const route = useRoute();
MovieApiService.getMovie(route.params.id).then((response) => {
movie.value = response.data.results;
});
return {
movie,
};
},
method: {},
};
Method being called:
static getMovie(body: GetMovieByTmdbId) {
return axios.get(
`https://api.themoviedb.org/3/movie/${body.id}?api_key=${apiKey}`
);
}
Here's what I tried to compute the property instead, with the same result.
setup() {
const route = useRoute();
const id = computed(()=>{return route.params.id})
const movie = ref([]);
getMovie(id).then((response) => {
movie.value = response.data.results;
console.log(movie.value);
});
How should I ensure this value is available when I call my method?
You are giving route.params.id as a variable to getMovie(body).
You are then using body.id in your URL. This would equal route.params.id.id which is not defined.
Use body in your URL, or change the parameter to id so is makes more sense.
Like this:
...
const route = useRoute();
MovieApiService.getMovie(route.params.id).then((response) => {
movie.value = response.data.results;
});
...
const getMovie = (id) => {
return axios.get(
`https://api.themoviedb.org/3/movie/${id}?api_key=${apiKey}`
);
}

How to get item by Id using Vue 3 Composition API using Axios

Im struggling using Axios and useRoute using Axios with Composition API. Here is the code on how to do it in using the Option API, how do I recreate it, the Vue-router docs not well documented at all right now.
async created() {
const result = await axios.get(`https://localhost:5001/api/artists/${this.$route.params.id}`
);
const artist = result.data;
this.artist = artist;
},
To convert that code to Composition API:
created() hook is effectively the same timing as setup(), so put that code in setup().
this.$route can be accessed via useRoute() (from vue-router#4).
artist can be declared as a data ref, returning it from setup() if used in the template.
To reactively fetch data from the API based on the id parameter, use watch on route.params.id. This watch call returns a function that stops the watcher, which is useful if you need to conditionally unwatch the reference.
import { useRoute } from 'vue-router'
import { ref, watch } from 'vue'
export default {
// 1
setup() {
const route = useRoute() // 2
const artist = ref(null) // 3
// 4
const unwatch = watch(() => route.params.id, (newId, oldId) => {
const result = await axios.get(`https://localhost:5001/api/artists/${newId}`)
artist.value = result.data
// run only once
unwatch()
})
return {
artist
}
}
}

Nuxt Fetch Doesn't Update on First Load

I'm having the following issue and hope someone could help me on it:
Fetch is not working on the first load (nor on reloads). It only works when on the client-side (when I move between routes).
I've read that watchQuery could help but didn't understand why and how to use it.
<script>
export default {
async fetch() {
const userId = await this.$nuxt.context.store.state.auth.authUser.userId
await this.$store.dispatch('case/fetchMyCases', userId.uid)
await this.$store.dispatch('case/fetchMyPendingCases', userId.uid)
...
It doesn't work even if I import and use firebase/auth directly.
<script>
import * as firebase from 'firebase/app'
import 'firebase/auth'
export default {
async fetch() {
const userId = await firebase.auth().currentUser
await this.$store.dispatch('case/fetchMyCases', userId.uid)
await this.$store.dispatch('case/fetchMyPendingCases', userId.uid)
...
Does anyone have any tips for it? I'd really appreciate it.
Thanks!
After literally 3 days searching/testing, I finally found out why I was having this issue.
The problem was that I simply put async/await for fetch but didn't put async/await for the actions itself. Therefore, my getter (in computed) was getting the store state before the dispatches have been finished.
Thanks, everyone!
Warning: You don't have access of the component instance through this inside fetch because it is called before initiating the component (server-side).
async fetch({ store }) {
await store.dispatch('case/fetchMyCases')
await store.dispatch('case/fetchMyPendingCases')
}
If you need parameter:
async fetch({ store, params }) {
await store.dispatch('case/fetchMyCases', params.uid)
await store.dispatch('case/fetchMyPendingCases', params.uid)
}
I gave an example of id. The name of the parameter depends on the name of your page.
_id => params.id
_uid => params.uid
_slug => params.slug
...
Yes, You must put async/await on actions.
async automatically returns a promise
If you don't need the value, in this case, don't anything return.
export const Actions = {
async fetchUsers() {
// It will return automatically promise
await this.$axios.get('API')
}
}
// If you need returne value
// First way
export const Actions = {
async fetchUsers() {
// It will return promise and value
return await this.$axios.get('API')
}
}
// Second way
export const Actions = {
async fetchUsers() {
// It will return promise and value
const response = await this.$axios.get('API')
return response;
}
}