its passing as combined values 4,5,6 - javascript

I am new to promise.
I need to make two different api calls.
from the result of first api call I am getting id in the variable firstAPIid,
https://reqres.in/api/users?page=2
I need to pass this id firstAPIid to the second api call.
but the problem is its passing as combined values 4,5,6 https://jsonplaceholder.typicode.com/comments?postId=4,5,6
from the second api call I need to retrieve email and display it in the browser.
do I need to use promise or async or with redux itself can I achieve it.
I researched and referred the below links but still no luck
https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8
can you tell me how to fix it.
providing my code snippet and sandbox below
https://codesandbox.io/s/redux-async-actions-xjdo7
<FetchButton
onFetchClick={() => {
store.dispatch(dispatchFunc => {
dispatchFunc({ type: "FETCH_DATA_START" });
axios
.get("https://reqres.in/api/users?page=2")
// axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log("response.data.data---->", response.data.data);
console.log(
"response.data.data[0].id---->",
response.data.data[0].id
);
dispatchFunc({
type: "RECEIVED_DATA",
payload: response.data.data
});
let firstAPIid = response.data.data.map(obj => {
return obj.id;
});
console.log("firstAPIid---->", firstAPIid);
return new Promise((resolve, reject) => {
//var url = `https://jsonplaceholder.typicode.com/comments?postId=3`;
var url =
`https://jsonplaceholder.typicode.com/comments?postId=` +
firstAPIid;
//response.data.data[0].id;
console.log("second url---->", url);
axios
.get(url)
.then(response => {
var lFilterData = "";
//memberGroupingHelper.filterData(response.data, additionalParams);
resolve(lFilterData);
})
.catch(error => {
if (error.response) {
console.log(
`############## service error from helpeeeeeer reject`
);
}
reject("");
});
});
})
.catch(err => {
dispatchFunc({ type: "FETCH_DATA_ERROR", payload: err });
});
});
}}
/>

I found your issue. It is happening because you are not processing the result of the promise. To do that just add the .then() and .catch() functions:
<FetchButton
onFetchClick={() => {
store.dispatch(dispatchFunc => {
dispatchFunc({ type: "FETCH_DATA_START" });
axios
.get("https://reqres.in/api/users?page=2")
// axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log("response.data.data---->", response.data.data);
console.log(
"response.data.data[0].id---->",
response.data.data[0].id
);
dispatchFunc({
type: "RECEIVED_DATA",
payload: response.data.data
});
let firstAPIid = response.data.data.map(obj => {
return obj.id;
});
console.log("firstAPIid---->", firstAPIid);
return new Promise((resolve, reject) => {
//var url = `https://jsonplaceholder.typicode.com/comments?postId=3`;
var url =
`https://jsonplaceholder.typicode.com/comments?postId=` +
firstAPIid;
//response.data.data[0].id;
console.log("second url---->", url);
axios
.get(url)
.then(response => {
var lFilterData = "";
//memberGroupingHelper.filterData(response.data, additionalParams);
resolve(lFilterData);
})
.catch(error => {
if (error.response) {
console.log(
`############## service error from helpeeeeeer reject`
);
}
reject("");
});
}).then((previousResponse) => {
//Here you resolved the promise with the resolve value above
console.log(previousResponse)
}).catch((error) => {
//Here you resolved the promise with the reject value above
console.log(error);
});
})
.catch(err => {
dispatchFunc({ type: "FETCH_DATA_ERROR", payload: err });
});
});
}}
/>
I am not seeing any use of the Promise because what you want to achieve can be done just with axios.
EDIT:
Just with axios you can get it. Modify as below:
<FetchButton
onFetchClick={() => {
store.dispatch(dispatchFunc => {
dispatchFunc({ type: "FETCH_DATA_START" });
axios
.get("https://reqres.in/api/users?page=2")
// axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log("response.data.data---->", response.data.data);
console.log(
"response.data.data[0].id---->",
response.data.data[0].id
);
//First of all we'll create the number of requestes base on the previous Response
const promises = response.data.data.reduce((previousValue, { id }) => {
previousValue.push(axios.get(`https://jsonplaceholder.typicode.com/comments?postId=${id}`));
return previousValue;
},[]);
//We use the built in function to fetch the data
axios.all(promises)
.then((responses) => {
//Here you have all responses processed
const emailsMapped = responses.reduce((previousValue, { data }) => {
const emails = data.map(({ email }) => email)
previousValue.push(...emails);
return previousValue;
}, [])
//You send the emails you want
dispatchFunc({
type: "RECEIVED_DATA",
payload: emailsMapped
});
console.log(emailsMapped);
})
})
.catch(err => {
dispatchFunc({ type: "FETCH_DATA_ERROR", payload: err });
});
});
}}
/>
Also modifies this line in DataList without the first_name
listItems.push(<div key={fetchedDataId++}>{elem}</div>);

Related

Data not returning from service to context when using promises

I'm getting some data from server and have set-up this service on client to request them accordingly:
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
const { data } = await axios.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
return data
}
service is called within context:
const syncFollowedArtists = async () => {
await spotifyService
.serviceSyncFollowedArtists(user.userId)
.then(res => {
if (res.length === 0) return
dispatch({
type: 'SYNC',
data: res,
})
})
.catch(err => {
console.log(err)
})
}
It works fine as I want it to, however, before, I have set up the service to request data using promises:
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
await axios
.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
.then(res => {
return res.data
})
.catch(err => {
console.log(err.message)
})
}
Even though I manage to obtain the data from server inside the service, when it's returned to the function in context, it's empty, undefined. Is threre any reason for this?
You are getting undefined because you are not returning anything from the function in the case of promises, unlike you are doing it in the first case
So just add a return keyword
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
return await axios
.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
.then(res => {
return res.data
})
.catch(err => {
console.log(err.message)
})
}

Axios prints value on console but returns undefined

I have quite an issue for some time and is getting on my nerves and it doesn't make sense. I have used axios on my react frontend and it works perfect when assigning the get value to the state. But when using it in a normal javascript code, I appear to have this following issue: i can print the object's value in the console but it will return only undefined.. Here is my code:
login = () => {
let data;
axios.get('https://myaddress/authenticate')
.then(response => {
data = response;
console.log('data here', data);
})
.catch(error => {
console.error('auth.error', error);
});
console.log('eee', data);
return data;
};
Here we are talking about axios strictly.
You can't return an ajax response because it's asynchronous. You should wrap your function into a promise or pass a callback to login
UPDATE: As #Thilo said in the comments, async/await would be another option, but it will let you set the response to data tho ...
1. Wrap into a promise
login = () => new Promise((resolve, reject)=>{
axios.get('https://myaddress/authenticate')
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
});
});
// Usage example
login()
.then(response =>{
console.log(response)
})
.catch(error => {
console.log(error)
})
2. Pass a callback
login = (callback) => {
axios.get('https://myaddress/authenticate')
.then(response => {
callback(null,response)
})
.catch(error => {
callback(error,null)
});
};
// Usage example
login((err, response)=>{
if( err ){
throw err;
}
console.log(response);
})
3. Async/Await
login = async () => {
// You can use 'await' only in a function marked with 'async'
// You can set the response as value to 'data' by waiting for the promise to get resolved
let data = await axios.get('https://myaddress/authenticate');
// now you can use a "synchronous" data, only in the 'login' function ...
console.log('eee', data);
return data; // don't let this trick you, it's not the data value, it's a promise
};
// Outside usage
console.log( login() ); // this is pending promise
In ES7/ES8 you can do async/await like a boss:
login = () => {
return new Promise((resolve, reject) => {
axios.get('https://myaddress/authenticate')
.then(response => {
resolve(response)
})
.catch(error => {
console.error('auth.error', error);
reject(error)
});
});
};
async function getData() {
try{
const data = await login()
} catch(error){
// handle error
}
return data;
}
getData()
.then((data) => console.log(data));

Why is this promise not resolving back to the caller?

I have a Vue-App which runs with Vuex and Axios. In this app I have vuex-store which handles API-calls, but a problem is that when I call the store-actions I cant chain the response in the caller.Any ideas what Im doing wrong?
Calling code:
import { FETCH_PRODUCTS, ADD_PRODUCT } from './actions.type'
methods: {
sendNewProduct () {
this.$store
.dispatch(ADD_PRODUCT, this.newProductForm)
.then(() => {
console.log('This never gets called')
})
}
}
Vuex-store:
const actions = {
[ADD_PRODUCT] (context, credentials) {
return new Promise((resolve) => {
ApiService
.post('/Products/', {
Name: credentials.Name,
Description: credentials.Description,
Price: credentials.Price
})
.then(({ data }) => {
this.$store
.dispatch(FETCH_PRODUCTS)
resolve(data)
})
.catch(({ response }) => {
console.log(response)
context.commit(SET_ERROR, 'Error adding product')
})
})
}
}
const actions = {
[ADD_PRODUCT](context, credentials) {
return ApiService.post("/Products/", {
Name: credentials.Name,
Description: credentials.Description,
Price: credentials.Price
})
.then(({ data }) => {
this.$store.dispatch(FETCH_PRODUCTS);
return data;
})
.catch(({ response }) => {
console.log(response);
context.commit(SET_ERROR, "Error adding product");
throw new Error("Error adding product");
});
}
};
I've removed the new Promise(...) because axios already creates a promise.
If added a return data in the then callback and a throw in the catch callback to let the calling api receive the data/error.
Note that the promise resolves before the FETCH_PRODUCTS completes, to make sure that action is also completed, you'd write:
.then(({ data }) => {
return this.$store.dispatch(FETCH_PRODUCTS)
.then(() => data);
})

How do I mock two fetches or one Promise and one fetch?

I am trying to test the loadAllProjects function.
The test fails at .then() with the error: TypeError: Cannot read property 'then' of undefined
I have also tried mocking the reponse of getHeadersWithToken() but could not get it to work.
Snookered on this one and would appreciate any help.
test:
it('should create SET_ALL_PROJECTS action when fetching projects', () => {
fetch
.once(JSON.stringify([{ access_token: "12345" }]))
.once(JSON.stringify({ name: "x" }))
const expectedActions = [
{ type: "SET_ALL_PROJECTS", json: { name: "x" } },
]
store.dispatch(actions.loadAllProjects.apply())
.then(() => { // FAILS HERE
expect(store.getActions()).toEqual(expectedActions)
})
});
code:
export const getHeadersWithToken = () => {
return fetch("/.auth/me", requestOptions)
.then(parseResponseAndHandleErrors)
.then(json => {
const header = 'Bearer ' + json[0].access_token
const applicationJsonHeaders = getJsonHeaders(header)
return applicationJsonHeaders
})
.catch( error=> {
console.error(error)
})
}
export const loadAllProjects = () => {
return (dispatch) => {
getHeadersWithToken()
.then(applicationJsonHeaders => {
const requestOptions = {
method: 'GET',
headers: applicationJsonHeaders,
};
return fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
.then(parseResponseAndHandleErrors)
.then(json => {
dispatch(setAllProjects(json))})
.catch(error => {
console.error(error)
dispatch(failedToLoadProjects(error))
});
})
}
}
store used in test:
const store = mockStore(Map(
{
allProjects: Map({
}),
currentProject: Map({
authenticationData: Map({
})
})
})
);
What Redux middleware are you using for the async stuff? Make sure you set up the middleware when creating the store for testing.
Since i dont see that anywhere in your code above im gonna assume we are not using that middleware here.
Since loadAllProjects is a higher order function i would do this:
it('should create SET_ALL_PROJECTS action when fetching projects', (done) => {
fetch
.once(JSON.stringify([{ access_token: "12345" }]))
.once(JSON.stringify({ name: "x" }))
const expectedActions = [
{ type: "SET_ALL_PROJECTS", json: { name: "x" } },
]
// Higher order function that returns a new function.
const loadAllProjectsAsync = actions.loadAllProjects();
// The function returned expects a dispatch from Redux as an argument.
// It will do async work and when its done, it will call the provided dispatch.
loadAllProjectsAsync(store.dispatch).then(() => {
expect(store.getActions()).toEqual(expectedActions);
done();
})
});
You also need to modify your code for loadAllProjects so that the inner function returns the promise:
export const loadAllProjects = () => {
return (dispatch) => {
// You will need to return the promise in order for the test to be able to call .then() on it.
return getHeadersWithToken()
.then(applicationJsonHeaders => {
const requestOptions = {
method: 'GET',
headers: applicationJsonHeaders,
};
return fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
.then(parseResponseAndHandleErrors)
.then(json => {
dispatch(setAllProjects(json))})
.catch(error => {
console.error(error)
dispatch(failedToLoadProjects(error))
});
})
}}
Also, as already stated, you must tell the jest when the test is done if you are testing async stuff. Do this by letting your it call take done as a param and call that as a function after you have verified the outcome i the .then()
This was just a quick fix from my side. There still might be something im missing or some bugs in the code above, but you get the point.
Let me know if you have any follow up questions?
In case this is ever useful to anyone and in acknowledgment of Septastium's answer, I eventually changed the code to:
async getHeadersWithToken(requestType) {
if (process.env.REACT_APP_RUNNING_LOCALLY==="true") {
return {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
};
}
let result = await fetch("/.auth/me", this.requestOptions)
let headers = result.json()
.then( json => {
const header = 'Bearer ' + json[0].access_token
const applicationJsonHeaders = this.getJsonHeaders(header, requestType)
return applicationJsonHeaders
})
.catch(error => {
console.error(error)
})
return headers
}
export const loadAllProjects = () => {
return async dispatch => {
const authenticator = new Authenticator()
let applicationJsonHeaders = await authenticator.getHeadersWithToken(constants.GET)
let loggedInUser = await authenticator.getLoggedInUser()
const requestOptions = {
method: 'GET',
headers: applicationJsonHeaders,
};
return await fetch(process.env.REACT_APP_PROJECTS_API_URL + "/projects", requestOptions)
.then(response => {
return parseResponseAndHandleErrors(response)
})
.then(json => dispatch(setAllProjects(json)))
.then(()=> dispatch(setAuthenticationData(loggedInUser)))
.catch(error => {
console.error(error)
return dispatch(failedToLoadProjects(error))
});
}
}
and the test to:
const checkActionsWereDispatched = async (expectedActions, actionCreator) => {
const store = mockStore(Map(
{
}),
);
store.dispatch(await actionCreator.apply()).then(() => {
expect(store.getActions()).toEqual(expectedActions)
})
}
it('should create SET_ALL_PROJECTS action when fetching projects', async () => {
fetch
.once(JSON.stringify([{ access_token: "12345" }]))
.once(JSON.stringify({ name: "x" }))
const expectedActions = [
{ type: "SET_ALL_PROJECTS", json: { name: "x" } },
]
checkActionsWereDispatched(expectedActions, actions.loadAllProjects)
});
As noted above I think Spetastium's version of the test is easier to read than mine and his article here was very helpful.

react.js: Create resource with redux-form, rest api and async/await

I'm trying to create new resource with redux form and REST api.
I dispatch createPost action and I want to check if the post was succeeded before continue.
const handleFormSubmit = (values, dispatch) => {
dispatch(createPost(values));
//I want to check here if post was succeeded.
//if status = 200 this.props.history.push('/');
}
export function createPost(values) {
return async function(dispatch) {
let request;
try {
request = await axios.post(`${ROOT_URL}/posts`, values)
} catch(err) {
request = { err };
}
dispatch({
type: CREATE_POST,
payload: request
})
}
}
Return a promise, something like this :
export function createPost(values) {
return function(dispatch) {
return new Promise( async function(resolve, reject){
let request;
try {
request = await axios.post(`${ROOT_URL}/posts`, values)
} catch(err) {
reject(err)
}
dispatch({
type: CREATE_POST,
payload: request
})
resolve(request)
})
}
}
const handleFormSubmit = () => {
dispatch(createPost(values))
.then( res => {
// do yoour stuff on succes
} )
.catch(err => {
// stuff on err
})
}
As seeing your codes, I don't think you need to use promise.
Please try like following:
const getAction = (values) => (dispatch) => {
return axios
.post(`${ROOT_URL}/posts`, values)
.then(
() => {
dispatch({
type: CREATE_POST,
payload: request
})
},
() => {
throw new SubmissionError({
_error: 'Failed'
});
}
);
};
const handleSubmit = (values) => {
return dispatch(getAction(values));
};

Categories