Parent compoment:
const { getGroup, removePubli, removeTablet, loadTotal, error } = useGroups();
const group = ref({});
getGroup(group_id).then((g) => {
group.value = g;
});
Child component:
const { group } = defineProps({
group: {
type: Object,
default: {},
},
});
Given the prop above, which is fetched by an async axios call, when I try to use it in a chield component it is undefined or a promise.
I've already tried to put an async inside onMounted hook but it doesn't work.
getGroup does it:
const getGroup = async (id) => {
const r = await api.get(`/api/v1/groups/${id}`);
if (r?.status !== 200) error.value = "Falhou";
return r.data;
};
I want to await it before the code continues or find a way to do something when the promise resolves itself.
I don't see in your code any await. Use await instead of .then!
<script setup>
const { getGroup, removePubli, removeTablet, loadTotal, error } = useGroups();
const group = ref({})
const result = await getGroup(someId)
group.value = result.data // or what ever
</script>
Related
I've been struggling for 5 hours with the following issue.
I have a service file where I have API calls using Axios. In the store, I have an action that uses the service to pull a list of schools, then I commit the data to the mutations. If I console log the data on the mutation object, it works correctly and shows the data. However, when I call dispatch from the component inside the onMounted hook, I get an empty object. Any help is greatly appreciated. (see the code below)
store/schools.js
export const state = () => ({
mySchools: []
});
export const mutations = {
getSchools(state, data) {
state.schools = data;
console.log(state.schools); // works;
}
};
export const actions = {
async getMySchools({ commit }) {
await this.$getSchools().then(response => {
commit("getSchools", response.data);
});
}
};
portal/dashboard.vue
import {onMounted, ref, useStore} from "#nuxtjs/composition-api";
export default {
layout: 'portal',
setup() {
const store = useStore();
const schools = ref([]);
onMounted(async() => {
await store.dispatch('schools/getMySchools'); // is not pulling data
schools.value = store.state.schools.mySchools;
console.log(schools); // empty
});
return {
schools
}
}
};
Thank you
You shouldn't use await with then
try this
async getMySchools({ commit }) {
const response = await this.$getSchools();
commit("getSchools", response.data);
}
I'm assuming that your this.$getSchools() actually works since I'm not sure what that is and it's not part of the code
I have a store which is just an array of strings.
I am trying to watch it and do a search when it has changed.
Originally I had a computed value a bit like this:
const { value } = computed(() => {
const urls = store.getters.wishlist;
filters.value = createFilters("IndexUrl", urls);
return useListProducts(page.value, filters.value);
});
which I returned like this:
return { ...value, skip, more };
This worked fine when loading the page the first time, but if another component adds/removes something from the wishlist I want the function to fire again.
For context, here is the whole component:
import {
computed,
defineComponent,
getCurrentInstance,
ref,
} from "#vue/composition-api";
import Product from "#components/product/product.component.vue";
import {
createFilters,
createRequest,
useListProducts,
} from "#/_shared/logic/list-products";
export default defineComponent({
name: "Wishlist",
components: { Product },
setup() {
const instance = getCurrentInstance();
const store = instance.proxy.$store;
const page = ref(1);
const skip = ref(0);
const filters = ref([]);
const { value } = computed(() => {
const urls = store.getters.wishlist;
filters.value = createFilters("IndexUrl", urls);
return useListProducts(page.value, filters.value);
});
const more = () => {
skip.value += 12;
page.value += 1;
const request = createRequest(page.value, filters.value);
value.fetchMore({
variables: { search: request },
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) return prev;
return {
search: {
__typename: prev.search.__typename,
hasMoreResults: fetchMoreResult.search.hasMoreResults,
total: fetchMoreResult.search.total,
facets: [...prev.search.facets, ...fetchMoreResult.search.facets],
items: [...prev.search.items, ...fetchMoreResult.search.items],
},
};
},
});
};
return { ...value, skip, more };
},
});
So I figured that the issue was that I wasn't actually watching anything, so I removed the computed method and instead decided to setup a watch. First I created a listProducts method:
const result = reactive({
result: null,
loading: null,
error: null,
fetchMore: null,
});
const listProducts = (urls: string[]) => {
console.log(urls);
filters.value = createFilters("IndexUrl", urls);
Object.assign(result, useListProducts(page.value, filters.value));
};
And then I invoked that in my setup:
listProducts(store.getters.wishlist);
Then I setup a watch:
watch(store.getters.wishlist, (urls: string[]) => listProducts(urls));
What I expected to happen, was that when an item was added/remove from the wishlist store, it would then invoke listProducts with the new set of urls. But it didn't fire at all.
Does anyone know what I am doing wrong?
I believe the issue is with destructuring the reactive property, on destructuring you assign the properties to variables and no longer have a proxy to react to changes..try
return { value, skip, more };
and reference the property in your template
<template>
{{value.foo}}
</template
this question has to do with setup props but the same concept applies
Vue 3 watch doesn’t work if I watch a destructured prop
I am using Nuxt.js and want to test my page which uses asyncData with Jest. I have a factory function to set up my wrapper, but it basically returns a shallowMount.
Expected
When clicking a button I want the function to behave differently depending on the query parameter. When running the test I want to mock this by setting it directly when creating the wrapper (Similar to setting propsData). E.g. const wrapper = factory({ propsData: { myQueryParam: 'some-value' } });
Result
However trying to set propsData still returns undefined: console.log(wrapper.vm.myQueryParam); // undefined while I would expect it to be 'some-value'
Question
Is there a different approach on how I can test this function that relies on query parameters?
Because asyncData is called before Vue is initialised, it means shallowMount doesn't work right out of the box.
Example:
page:
<template>
<div>Your template.</div>
</template>
<script>
export default {
data() {
return {}
},
async asyncData({
params,
error,
$axios
}) {
await $axios.get("something")
}
}
</script>
test:
import { shallowMount } from "#vue/test-utils";
describe('NewsletterConfirm', () => {
const axiosGetMock = jest.fn()
const axiosPostMock = jest.fn()
var getInitialised = async function (thumbprint) {
if (thumbprint == undefined) throw "thumbprint not provided"
let NewsletterConfirm = require('./_thumbprint').default
if (!NewsletterConfirm.asyncData) {
return shallowMount(NewsletterConfirm);
}
let originalData = {}
if (NewsletterConfirm.data != null) {
originalData = NewsletterConfirm.data()
}
const asyncData = await NewsletterConfirm.asyncData({
params: {
thumbprint
},
error: jest.fn(),
$axios: {
get: axiosGetMock,
post: axiosPostMock
}
})
NewsletterConfirm.data = function () {
return {
...originalData,
...asyncData
}
}
return shallowMount(NewsletterConfirm)
}
it('calls axios', async () => {
let result = await getInitialised("thumbprint")
expect(axiosGetMock).toHaveBeenCalledTimes(1)
});
});
Credits to VladDubrovskis for his comment: in this nuxt issue
I am trying to debounce a method within a Vuex action that requires an external API.
// Vuex action:
async load ({ state, commit, dispatch }) {
const params = {
period: state.option.period,
from: state.option.from,
to: state.option.to
}
commit('SET_EVENTS_LOADING', true)
const res = loadDebounced.bind(this)
const data = await res(params)
console.log(data)
commit('SET_EVENTS', data.collection)
commit('SET_PAGINATION', data.pagination)
commit('SET_EVENTS_LOADING', false)
return data
}
// Debounced method
const loadDebounced = () => {
return debounce(async (params) => {
const { data } = await this.$axios.get('events', { params })
return data
}, 3000)
}
The output of the log is:
[Function] {
cancel: [Function]
}
It is not actually executing the debounced function, but returning to me another function.
I would like to present a custom debounce method which you can use in your vuex store as
let ongoingRequest = undefined;
const loadDebounced = () => {
clearTimeout(ongoingRequest);
ongoingRequest = setTimeout(_ => {
axios.get(<<your URL>>).then(({ data }) => data);
}, 3000);
}
This method first ensures to cancel any ongoing setTimeout in the pipeline and then executes it again.
This can be seen in action HERE
I'm currently building a Hacker News Reading Client in React Native using their Official API
I want to display the top stories of the day. So first I get the id's of the top posts for the day and then use those id's to fetch the stories.
But when I run this the promise gets rejected with ids.map is undefined.
How can I fix this ?
FeedScreen.js
import { getTopStoriesID, getStoriesByID } from '../../hacknews-api';
class FeedScreen extends Component {
constructor(props) {
super(props);
this.state = {
loaded: false,
stories: [],
};
}
async componentDidMount() {
const storiesID = await getTopStoriesID();
const stories = await getStoriesByID(storiesID[10]);
this.setState({ stories });
}
render() {
return <Text>{this.state.stories}</Text>;
}
}
export default FeedScreen;
hacknews-api.js
const BASE_URL = 'https://hacker-news.firebaseio.com/v0';
export const getTopStoriesID = async () => {
const res = await fetch(BASE_URL + '/topstories.json');
const storiesID = await res.json();
return storiesID;
};
export const getStoriesByID = async (ids) => {
const res = await Promise.all(ids.map(async (id) => {
const res = await fetch(BASE_URL + `/item/{id}.json`)
const story = await res.json();
return story;
}));
const stories = await res.json();
return stories;
}
You can use Array.prototype.map() on an array and not an object.
The map() method creates a new array with the results of calling a
provided function on every element in the calling array.
Example
export const getStoriesByID = async (ids) => {
// check if the argument is defined and its an Array
if(ids && ids.constructor === Array) {
// do something with array of ids, for example do a map()
} else {
// do something otherwise
}
}