Vue 3 using function inside setup - javascript

I am doing a simple app and I am using mock-json-server to simulate http request.
I have defined a function to get the info I need :
import { ref } from 'vue'
const getScores = () => {
const scoringPass = ref([])
const error = ref(null)
const load = async () => {
try {
let data = await fetch('http://localhost:8000/scores', {
method: 'get',
headers: {
'content-type': 'application/json'
}})
if (!data.ok) {
throw Error('no data available')
}
scoringPass.value = await data.json()
console.log(scoringPass.value)
} catch (err) {
error.value = err.message
console.log(error.value)
}
}
return { scoringPass, error, load }
}
export default getScores
And I call it in the setup function of my component :
<script lang="ts">
import { defineComponent } from 'vue'
import Pass from '#/components/Pass.vue'
import getScores from '../composables/getScores.js'
export default defineComponent({
setup() {
const numeroDossier = '25020230955000004'
const { scoringPass, error, load } = getScores()
load()
return { numeroDossier, scoringPass, error }
},
components: {
Pass,
},
})
</script>
In the console.log(scoringPass.value) in the function, I can see the data. but the load() function in the setup part does not work and I can't figure out why. It is called though, but I can't get the data.
When I do console.log(load()), I get :
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
Any help appreciated.
Cheers.

load() is async, so its return value is a Promise. You have to await the call to get the underlying data. However, load() doesn't actually return anything, so you still wouldn't see any data. If you want load() to provide the initial value of scoringPass, load() should return that:
const load = async () => {
try {
⋮
return scoringPass.value
} catch (err) {
⋮
return null
}
}
To get the result of load(), you can wrap the call in an async function to await the call; or chain a .then() callback:
export default defineComponent({
setup() {
⋮
const logLoadResults = async () => console.log(await load())
logLoadResults()
// or
load().then(results => console.log(results))
}
})
Don't mark setup() as async because that would make your component an async component, requiring a <Suspense> in a parent component to render it.

Related

How to wait for axios function to return value when in service class

I want to structure my application with some sort of service class, but whenever I extract my axios calls from the page, then the axios function seems to return "undefined".
My page looks like this. The signin function is called when the user hits the button. When I put the axios call in the page like this, everything works fine. The usestate is updated and displays.
export default function AccountPage() {
const [signinResponse, setSigninResponse] = useState();
async function signin() {
await axios
.get(
`...url...`
)
.then((res) => {
setSigninResponse(res)
});
}
...
However, when I take the axios function and move it to a service class like this
import axios from "axios";
export async function tableauSignin() {
await axios
.get(
`...url...`
)
.then((res) => {
console.log(res);
return res;
});
}
and then import and make the call like this
import { tableauSignin } from "../services/tableau-online.service";
...
export default function AccountPage() {
const [signinResponse, setSigninResponse] = useState();
async function signin() {
const r = await tableauSignin();
setSigninResponse(r);
console.log(r);
}
...
the log from the service class is good but the log on the account page is undefined.
As #RobinZigmond mentioned in comment. The following solution will work but it's a needless.
it's a needless verbose way of just doing export function
tableauSignin() { return axios.get(url).then(response =>
response.data) }.
export async function tableauSignin() {
return await axios.get(url).then(response => response.data)
}
This Solution may be more useful
const getData = async () => {
let res = await axios.get("url");
let { data } = res.data; //or res
return data;
};
You can also import this way
var response = await getData();

React useQuery hook running all the time inside the component

I have a problem where useQuery is always running in my application and I don't why
In my component
import { GET_DATA } from 'apiCalls';
const { loading, error, data } = useQuery('getData', GET_DATA(token));
In my api call
export const GET_DATA = async (token) => {
try {
const res = await axios.get(`${process.env.REACT_APP_SERVER}/api/...`, {
headers: {'auth-token': token},
});
console.log(res);
return res.data;
} catch (err) {
console.log('Error getting data');
return err;
}
}
when I debug my app. The function GET_DATA is always running ALL the time. what is the issue here ?
You must provide the useQuery only the function it wants to run, you must not call it inside useQuery. Provide the token to GET_DATA this way:
EDIT
As #tkdodo said we don't need to use the async function.
const { loading, error, data } = useQuery('getData', ()=>{
return GET_DATA(token);
});
The first solution I provided was this:
const { loading, error, data } = useQuery('getData', async()=>{
const data = await GET_DATA(token);
return data;
});
The root cause is the same as in React-Query, useQuery returns undefined only after loading is complete
The queryFn needs to be a function that returns a promise. GET_DATA does that. But by doing
GET_DATA(token) you directly invoke the function. So you’ll likely want:
() => GET_DATA(token) instead.
Try the following:
// apiCalls.js
export const getData = async (token) => {
try {
const res = await axios.get(`${process.env.REACT_APP_SERVER}/api/...`, {
headers: {'auth-token': token},
});
return res.data;
} catch (err) {
console.log('Error getting data');
return err;
}
// Component.js
import { getData } from 'apiCalls';
function Component(){
const { loading, error, data } = useQuery(
'getData',
()=>GET_DATA(token)
);
return (
<div>...</div>
)
}
useQuery should run in the component and the second parameter should not be a promise, but a function that returns a promise.

Wrapping getServerSideProps throws exception

I am trying to wrap getServersideProps with auth handler function, but keep getting this error:
TypeError: getServerSideProps is not a function
my wrapper looks like this:
export async function protect(gssp) {
return async (context) => {
const {req, res} = context;
const auth = await authHandler(req);
if (!auth.authenticated) {
res.statusCode = 302;
res.setHeader('Location', '/');
return;
}
context.auth = auth;
return await gssp(context);
}
}
and on the page, getServerSideProps looks like this:
export const getServerSideProps = protect(async function(context) {
return {
props: {
auth: context.auth
}
}
})
The call protect(...) actually returns a promise, rather than a function, since you explicitly declared it as async. To fix the issue you can simply remove the async from that function.
export function protect(gssp) {
// Remaining code untouched
}

Vue.js calling an async function from external js file

I am trying to create a .js file where I have a couple of my async calls.
I set up the file, but am not getting any results when I call my method.
This is all new to me to call from a .js file, so not sure what I am doing wrong.
Here is my inventory.js fileimport axios from "axios";
let getInventories = async () => {
const result = await axios
.get("/inventories")
.catch((error) => console.log(error));
// this.inventoryArray = result.data;
}
export {getInventories}
Here is the call from my Inventory.vue file
import axios from "axios";
import { bus } from "../app";
import {getInventories} from './inventory';
export default {
mounted() {
let temp = getInventories();
debugger;
},
}
temp not returning anything. I add await in from of getInventories but get an error
You're missing to return the result :
let getInventories = async () => {
try{
const result = await axios
.get("/inventories")
return result.data;
} catch(error){
console.log(error);
return null;
};
}
export {getInventories}

How to solve an error 'cb is not a function' in React Native?

current code
Index.js
import Auth from 'app/src/common/Auth';
export default class Index extends React.Component {
async componentDidMount() {
this.props.navigation.addListener('willFocus',
Auth.me().then(async (response) => {
await this.setState({ isLoggedIn: response });
}));
}
...
}
Auth.js
import axios from 'axios';
import { ENV } from 'app/env';
import { AsyncStorage } from 'react-native';
const { baseApiUrl } = ENV;
export default {
async me() {
try {
let result = false;
let token = await AsyncStorage.getItem('token');
token = token.replace(/"/g, '');
const response = await axios.get(`${baseApiUrl}/api/auth/me`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (response.data) {
result = true;
}
return result;
} catch (error) {
console.log(error);
}
},
};
error
I keep getting this error.
TypeError: cb is not a function. (In 'cb(data)', 'cb' is an instance of Promise)
I would appreciate it if you could give me any advice.
Its hard to tell without detail knowledge of your code (or react), but from the name i would expect this.props.navigation.addListener to take a callback function. Instead you pass a promise.
this.props.navigation.addListener('willFocus',
Auth.me().then(async (response) => {
await this.setState({ isLoggedIn: response });
})
);
Try changing the code to:
this.props.navigation.addListener('willFocus', () => {
Auth.me().then(async (response) => {
await this.setState({ isLoggedIn: response });
})
});
EDIT: #kai answer is better (and correct) for the current problem. I will leave the answer though, using async/await on the setState function is wrong anyway
You should remove the await from setState:
this.props.navigation.addListener('willFocus',
Auth.me()
.then((response) => {
this.setState({ isLoggedIn: response });
})
);
By using await, Javascript expects a Promise. But this.setState does not return a function.
On a sidenote, if you need to await for a setState function to be applied, you could use the callback as second parameter:
this.setState({ data }, () => console.log("Now the new state has been applied!"))
I resolved the same error by removing the listener from componentDidMount method
//this.props.navigation.addListener('focus', this._onFocus);

Categories