useQuery: custom names for `loading`, `error` and `data` props - react-native

Is there a way to use custom names for loading, error and data props? When I try it, I just get undefined:
const { queryLoading, queryError, queryData } = useQuery(someQuery);
This is not a big deal,just could not find anything in documentation and thought maybe there is some trick

you can do something like this:
const { data: queryData, error: queryError, loading: queryLoading } = useQuery(someQuery);

Related

accessing an array gives weird "refimpl"

I can't do data._rawValue or data._value to only get the arrays.
It doesn't recognize these keywords.
How should I approach this problem?
Thank you in advance.
there is a sample.
const data = ref([{ name: 1 }, { name: 2 }]);
const testClick = function () {
for (const item in data.value) {
console.log(data.value[item]);
console.log("hello");
}
console.log(data);
};
onMounted(() => {
testClick();
});
I think you may wrap the data with the ref function from vue.
Therefore,everytime you want to read the value from data,you had to read from the (data.value).
I suggest you to check the offical document of vue.
https://vuejs.org/api/reactivity-core.html#ref
Besides,if the type of data is object or array,its better to wrap it with reactive function.And then you can just read it directly.
I used to feel puzzle about this situation,too.
Im not good at writing in english.

vue-test-utils | TypeError: s.split is not a function

I try to run a test with vue-test-utils, including a component that has a mixin included, which has a function using split() on a string. The test looks like this:
describe('adminExample.vue Test', () => {
const wrapper = shallowMount(adminExample, {
global: {
mixins: [globalHelpers, authGatewayForElements, storeService],
plugins: [store]
}
})
it('renders component and is named properly', () => {
// check the name of the component
expect(wrapper.vm.$options.name).toMatch('adminExample')
})
})
adminExample.vue doesn't give any error, so I don't include it here, bit it uses a mixin.
The included mixin, called authGatewayForElements, has a function called decryptToken() and simply decrypt a jwt to get some info. The parameter userToken is declared within data of this mixin. The function looks like this:
decryptToken() {
let base64Split = this.userToken.split('.')[1];
let base64 = base64Split.replace(/-/g, '+').replace(/_/g, '/');
let jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
},
Running the test giving me the error TypeError: this.userToken.split is not a function . I´m new to testing with vue-test-utils and maybe or definitely missing something that needs to beincluded in the wrapper, as I expected functions like split() don't need to be included additionally.
EDIT: I get this error on multiple functions, like find(), so I'm pretty sure I just do something wrong. Thanks in advance to anybody pointing that out.

Event only firing as inline JS statement

I have the following code in a Nuxtjs app in SSR mode.
<Component
:is="author.linkUrl ? 'a' : 'div'"
v-bind="!author.linkUrl && { href: author.linkUrl, target: '_blank' }"
#click="author.linkUrl ? handleAnalytics() : null"
>
The click event in case it's an a tag, will only fire if it's written as handleAnalytics(), but handleAnalytics will not work.
Don't get me wrong the code is working, but I don't understand why.
With classical event binding (#click="handleAnalytics), Vue will auto bind it for you because it sees it's a function.
But when provided a ternary condition, it's not auto binded but wrapped into a anonymous function instead. So you have to call it with parenthesis otherwise you're just returning the function without executing it.
To be clearer, you can write it this way: #click="() => author.linkUrl ? handleAnalytics() : null"
Note: when having a dynamic tag component, I'd suggest to use the render function instead.
This is an advanced technique, but this way you won't bind things to an element that doesn't need it (without having the kind of hack to return null).
Example:
export default {
props: {
author: { type: Object, required: true },
},
render (h: CreateElement) {
const renderLink = () => {
return h('a', {
attrs: {
href: author.linkUrl,
target: '_blank',
},
on: {
click: this.handleAnalytics
},
)
}
const renderDiv = () => {
return h('div')
}
return this.author.linkUrl ? renderLink() : renderDiv()
}
}
Documention: Vue2, Vue3
In javascript functions are a reference to an object. Just like in any other language you need to store this reference in memory.
Here are a few examples that might help you understand on why its not working:
function handleAnalytics() { return 'bar' };
const resultFromFunction = handleAnalytics();
const referenceFn = handleAnalytics;
resultFromFunction will have bar as it's value, while referenceFn will have the reference to the function handleAnalytics allowing you to do things like:
if (someCondition) {
referenceFn();
}
A more practical example:
function callEuropeanUnionServers() { ... }
function callAmericanServers() { ... }
// Where would the user like for his data to be stored
const callAPI = user.preferesDataIn === 'europe'
? callEuropeanUnionServers
: callEuropeanUnionServers;
// do some logic
// ...
// In this state you won't care which servers the data is stored.
// You will only care that you need to make a request to store the user data.
callAPI();
In your example what happens is that you are doing:
#click="author.linkUrl ? handleAnalytics() : null"
What happens in pseudo code is:
Check the author has a linkUrl
If yes, then EXECUTE handleAnalytics first and then the result of it pass to handler #click
If not, simply pass null
Why it works when you use handleAnalytics and not handleAnalytics()?
Check the author has a linkUrl
If yes, then pass the REFERENCE handleAnalytics to handler #click
If not, simply pass null
Summary
When using handleAnalytics you are passing a reference to #click. When using handleAnalytics() you are passing the result returned from handleAnalytics to #click handler.

How to array destructure a Promise.all in Nuxt's asyncData

I am working with Nuxt and Vue, with MySQL database, all of which are new to me. I am transitioning out of WebMatrix, where I had a single Admin page for multiple tables, with dropdowns for selecting a particular option. On this page, I could elect to add, edit or delete the selected option, say a composer or music piece. Here is some code for just 2 of the tables (gets a runtime error of module build failed):
<script>
export default {
async asyncData(context) {
let [{arrangers}, {composers}] = await Promise.all([
context.$axios.get(`/api/arrangers`),
context.$axios.get(`/api/composers`),
])
const {arrangers} = await context.$axios.get('/api/arrangers')
const {composers} = await context.$axios.get('/api/composers')
return { arrangers, composers }
},
}
</script>
You do have the same variable name for both the input (left part of Promise.all) and as the result from your axios call, to avoid naming collision, you can rename the result and return this:
const { arrangers: fetchedArrangers } = await context.$axios.get('/api/arrangers')
const { composers: fetchedComposers } = await context.$axios.get('/api/composers')
return { fetchedArrangers, fetchedComposers }
EDIT, this is how I'd write it
async asyncData({ $axios }) {
const [posts, comments] = await Promise.all([
$axios.$get('https://jsonplaceholder.typicode.com/posts'),
$axios.$get('https://jsonplaceholder.typicode.com/comments'),
])
console.log('posts', posts)
console.log('comments', comments)
return { posts, comments }
},
When you destructure at the end of the result of a Promise.all, you need to destructure depending of the result that you'll get from the API. Usually, you do have data, so { arrangers } or { composers } will usually not work. Of course, it depends of your own API and if you return this type of data.
Since destructuring 2 data is not doable, it's better to simply use array destructuring. This way, it will return the object with a data array inside of it.
To directly have access to the data, you can use the $get shortcut, which comes handy in our case. Directly destructuring $axios is a nice to have too, will remove the dispensable context.
In my example, I've used JSONplaceholder to have a classic API behavior (especially the data part) but it can work like this with any API.
Here is the end result.
Also, this is what happens if you simply use this.$axios.get: you will have the famous data that you will need to access to later on (.data) at some point to only use the useful part of the API's response. That's why I do love the $get shortcut, goes to the point faster.
PS: all of this is possible because Promise.all preserve the order of the calls: https://stackoverflow.com/a/28066851/8816585
EDIT2: an example on how to make it more flexible could be
async asyncData({ $axios }) {
const urlEndpointsToFetchFrom = ['comments', 'photos', 'albums', 'todos', 'posts']
const allResponses = await Promise.all(
urlEndpointsToFetchFrom.map((url) => $axios.$get(`https://jsonplaceholder.typicode.com/${url}`)),
)
const [comments, photos, albums, todos, posts] = allResponses
return { comments, photos, albums, todos, posts }
},
Of course, preserving the order in the array destructuring is important. It's maybe doable in a dynamic way but I don't know how tbh.
Also, I cannot recommend enough to also try the fetch() hook alternative someday. I found it more flexible and it does have a nice $fetchState.pending helper, more here: https://nuxtjs.org/blog/understanding-how-fetch-works-in-nuxt-2-12/ and in the article on the bottom of the page.

Vue router: Dynamically set query key inside router.push()

I am new to Vue and I have created a project where I perform GET-requests based on current URL.
I have a function where I want to be able to set the dynamic value of filterType to the query key inside the router.push().
The function I have now just pushes filterType as a string. Ive been researching and havent found any answers regarding this issue. Grateful for any input or wisdom.
setFilter(filterType, filterValue){
if(filterValue){
this.$router.push({ query: Object.assign({}, this.$route.query, { filterType: filterValue })}).catch(err =>{});
}
else {
let query = Object.assign({}, this.$route.query);
delete query.filterType;
this.$router.replace({ query }).catch(err =>{});
}
},
Assign it as a key to the query object:
if(filterValue){
const query = this.$route.query
query[filterType] = filterValue
this.$router.push({path:'/', query:query})
}
Try this code
let newQuery = {filterType: filterValue};
this.$router.push({name: 'route-name', query: {...this.$route.query, ...newQuery}})