I have two functions, one is a page that calls for data from a function that gets data to and from a server.
The function that gets data to and from a server:
import React, { useEffect, useState, createRef, lazy, useContext } from "react";
import { UserContext } from "./UserContext";
import jwt_decode from "jwt-decode";
import axios from "axios";
export async function getProtectedAsset(url, user, setUser) {
try {
const res = await axios
.post(url, token)
.then((res) => {
console.log(res.data);
return res.data;
})
.catch((err) => {
console.error(err);
});
} catch (error) {
console.log(error);
throw err;
}
}
The code that calls this function:
useEffect(async () => {
try {
let res = await getProtectedAsset(
"http://127.0.0.1:5002/mypage",
user,
setUser
);
console.log(res);
} catch (error) {
console.error(error.message);
}
}, []);
getProtectedAsset will do a successful console.log(res.data); with the data from the server. The calling function that uses useEffect when doing console.log(res); will write undefined to the console.
Why can't I simply return from the function? Obviously the data is received from the server, but for some reason a function cannot return it? I am very confused
Thank you for your help!
You should not use async in useEffect. This is not supported.
I am not sure why you can't use getProtectedAsse(...).then(res=> {}).
But if you want to run getProtectedAsse() synchronously, try like the following instead.
useEffect(() => {
const asyncInternalFunc = async () => {
try {
let res = await getProtectedAsset(
"http://127.0.0.1:5002/mypage",
user,
setUser
);
console.log(res);
return res;
} catch (error) {
console.error(error.message);
}
}
asyncInternalFunc().then();
}, []);
Updated async function to return the response.
export async function getProtectedAsset(url, user, setUser) {
try {
const res = await axios.post(url, token);
return res;
} catch (error) {
console.log(error);
throw err;
}
}
Related
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.
I have a function, that connects to the API and returns the data:
import {API_KEY, API_URL} from "./constants";
// /**
// * Fetch all tasks
// * #param {function} successCallback - Function that saves incoming data
// */
export const getOperations = async (id, successCallback) => {
try {
const response = await fetch(`${API_URL}/tasks/${id}/operations`, {
headers: {
Authorization: API_KEY,
},
});
const data = await response.json();
if (data.error) {
throw new Error('Error!');
}
successCallback(data.data);
} catch (err) {
console.log(err);
}
};
Then, in one of my react component i call that function to get a data from the specified API:
The props is a required ID.
const [operations, setOperations] = useState([])
console.log(props)
useEffect(() => {
try {
getOperations(data => (props, setOperations(data)))
} catch(e) {
console.log(e)
}
}, [])
The problem is, that my API looks like:
`...api/tasks/function%20(data)%20%7B%20%20%20%20%20%20%20%20return%20props,%20setOperations(data);%20%20%20%`20%20%20%7D/operations`
So i receive 400 error.
Could someone explain me how to get API URL in this situation like:
/api/tasks/{id}/operations
Thanks in advance.
Rather than passing the callback to the result of the function, you could just return the data.
export const getOperations = async (id) => {
try {
const response = await fetch(`${API_URL}/tasks/${id}/operations`, {
headers: {
Authorization: API_KEY,
},
});
const data = await response.json();
if (data.error) {
throw new Error('Error!');
}
return data.data;
} catch (err) {
console.log(err);
}
};
useEffect(() => {
async function apiCall() {
try {
const data = await getOperations(props.id);
setOperations(data)
} catch(err) {
console.log(err)
}
}
apiCall();
}, [props.id])
Existing code:
loginUser.js:
import { getUserDetails } from '../api/userDetails';
import { mapApiObjectToModel } from '../mapper/userProfileMapper';
import axios from 'axios';
export const getLoggedInUserDetails = async () => {
axios
.get('/api/getUserDetails')
.then(response => {
return mapApiObjectToModel(response);
})
.catch(err => {
console.log('error==', err);
});
};
userProfileMapper.js:
export const mapApiObjectToModel = inputObj => {
const outputObj = {};
const authorizedRoles = ['Admin'];
if (inputObj) {
outputObj.fullName = '';
if (inputObj.data) {
outputObj.fullName = inputObj.data.data;
}
outputObj.role = 'Admin';
outputObj.isAuthorized = authorizedRoles.includes(outputObj.role);
}
console.log('outputObj', outputObj);
return outputObj;
};
loginUser.test.js:
import axios from 'axios';
import getLoggedInUserDetails from '../../action/loginUser';
jest.mock('axios');
describe('routes using memory router', () => {
it('Get Admin message', async () => {
const data = 'Admin';
axios.get.mockImplementationOnce(() => Promise.resolve(data));
console.log(data);
await expect(getLoggedInUserDetails()).resolves.toEqual(data);
expect(axios.get).toHaveBeenCalledWith('/api/getUserDetails');
});
it('fetches erroneously data from an API', async () => {
const errorMessage = 'Network Error';
axios.get.mockImplementationOnce(() => Promise.reject(new Error(errorMessage)));
await expect(getLoggedInUserDetails()).rejects.toThrow(errorMessage);
});
});
I'm really new to all these, so any assistance would be appreciated. Even any suggestions on TDD for userProfileMapper.js would be appreciated :)
The mapApiObjectToModel returns an object like,
{
role: 'ADMIN',
isAuthorized: true
}
However, in your test, you are expecting it to be equal to a string 'Admin'
const data = 'Admin';
...
await expect(getLoggedInUserDetails()).resolves.toEqual(data); // Note that you have initialize data to 'Admin'
Try changing data to be an object, like,
const data = {
role: 'Admin',
isAuthorized: true
};
...
await expect(getLoggedInUserDetails()).resolves.toEqual(data);
Updated: loginUser.js:
import { getUserDetails } from '../api/userDetails';
import { mapApiObjectToModel } from '../mapper/userProfileMapper';
import axios from 'axios';
export const getLoggedInUserDetails = () => {
return axios
.get('/api/getUserDetails')
.then(response => {
return mapApiObjectToModel(response);
})
.catch(err => {
console.log('error==', err);
throw err;
});
};
You function getLoggedInUserDetails had following issues,
You were not returning the promise from the function.
You don't need async here as you are accessing expect(Promise).resolves in your test file loginUser.test.js:.
You need to throw err from catch block, if you want to test the rejection of promise or remove the catch block.
I have updated following items to the function getLoggedInUserDetails,
removed the async from export const getLoggedInUserDetails = async () => {
returned promise from axios.get('/api/getUserDetails')
added throw err to catch block
You should not mix usage of Promise.then and async/await for more information on the difference between them check here and here
I have a js file named axios.js. Inside this file:
import axios from 'axios';
export function axiosGet (url, data, loading) {
axios.get(url, data, loading)
.then((response) => {
loading = false;
data = response.data;
})
.catch(error => console.log(error))
.finally(() => {
loading = true;
})
}
I have a Vue component where I import this function:
import {axiosGet} from '../axios.js'
mounted() {
axiosGet('https://jsonplaceholder.typicode.com/users', this.APIusers, this.isLoading);
}
where APIusers and isLoading are in data.
I get no error but it's not working.
What should I change to make it work?
Your problem is not related to importing function in vue component.
You have to change calling api function to this:
async mounted() {
this.isLoading = true;
const res = await axiosGet("https://jsonplaceholder.typicode.com/users");
if (res) {
this.APIusers = res;
}
this.isLoading = false;
}
and api function:
export async function axiosGet(url) {
try {
const response = await axios.get(url);
return response.data;
} catch (err) {
console.log(err);
}
}
here is working deme: https://codesandbox.io/s/hopeful-murdock-xqpws
this is my code:
export async function fetchData(searchValue) {
await fetch(`https://api.edamam.com/search?q=${searchValue}&app_id=${apiId}&app_key=${apiKey}`)
.then(res => res.json())
.then(
(result) => {
return result;
},
(error) => {
return (`Error: ${error}`);
}
)
}
The issue is:
I can't return the result to other component, but if I logged that value into the console, I can see the value, any help?
If I return the statement "await fetch" I can console log the object but I don't know how to access the data you can see on this image
Write your function like this:
export async function fetchData() {
try {
const response = await fetch(
`https://api.edamam.com/search?q=${searchValue}&app_id=${apiId}&app_key=${apiKey}`
);
return await response.json();
} catch (err) {
console.log(`Error: ${error}`);
}
}