I have a "answersRequest" function, gets the id of the answers it writes to the "b" list
const answersRequest = () => {
let b = [];
answers.map(answer => {
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
}).then(resp => {
b.push(resp.data.id)
})
})
}
And on completion of the map function, the below function needs to be run
const a = () => {setQuestionsBlok([...questionsBlok, {...questionBlokInputs, answers: b}]); setAnswers([])};
but I don't know how to find out when the map function ends
help me please
CodePudding user response:
You basically need to push the return values from the axios
call to an array and then use Promise.allSettled()
or Promise.all()
to wait for all the responses before you can continue processing that data.
// Just faking an axios call for this example:
function mockedAxios({ data }) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: {
id: Math.random().toString(36).substr(2, 9),
result: data * 2,
},
});
}, 1000 Math.random() * 2000)
});
}
async function answersRequest(answers) {
const promises = answers.map((answer) => {
// Return each promise here:
return mockedAxios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
});
// No need for a then block here, you can do it below in the `allSettled`'s `then`:
// .then((resp) => {
// return resp.data.id;
// });
});
// Wait for all responses and process the data:
const IDs = await Promise.allSettled(promises).then((result) => {
// result looks like { status: "fulfilled", value: { data: { id, result } } }
return result.map(r => r.value.data.id);
});
return IDs;
}
async function update() {
// You can now call and await this function from any other async function:
const IDs = await answersRequest([1,2,3,4,5]);
console.log(IDs);
// And then, one you get the result, do whatever you need to do with it:
// const a = () => {
// setQuestionsBlok([...questionsBlok, {...questionBlokInputs, answers: IDs }]);
// setAnswers([]);
// };
}
update();
CodePudding user response:
You can use Promise.all
to resolve all promises at once.
const answersRequest = () => Promise.all(
answers.map(answer =>
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
})
)
);
Promise.all
takes all the Promises passed to it (in this case, they are the HTTP requests) and only resolves when all the Promises are resolved. So, it's sending all the HTTP requests and waiting for all of them to finish. After that, the value of the returned Promise is an array containing all the responses, which means you don't need a separate variable for b
anymore.
Then you can use Promise.then
to call the second function.
answersRequest().then(values => {
setQuestionsBlok(
[...questionsBlok,
{
...questionBlokInputs,
answers: values.map(response => response.data.id)
}
]
);
setAnswers([]);
});
Here, values
is an array containing all the responses from the requests. Then, the map
call extracts all the id's from the response.
CodePudding user response:
At first you should enable asynchronous to your requests.
After that you can call the function at the end of the loop like this:
const answersRequest = () => {
let i = 0; // Loop counter
let b = [];
// It's called at the end of requests
const funcA = (b) => {
setQuestionsBlok([
...questionsBlok,
{...questionBlokInputs, answers: b}
])
setAnswers([])
}
// Post answers request function
const createAnswers = async (answer) => {
return await axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
})
}
answers.map(answer => {
i ; // Increase loop counter value
createAnswers(answer).then(resp => {
b.push(resp.data.id)
// Runs specified function at the end of requests
if(i === answers.length) {
funcA(b)
}
})
})
}
CodePudding user response:
You can use async/await to prompt your function to pause execution until a step completes:
const answersRequest = async () => {
let b = [];
await answers.map(answer => {
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
}).then(resp => {
b.push(resp.data.id)
})
})
// execution pauses here
setQuestionsBlok([...questionsBlok, {...questionBlokInputs, answers: b}]); setAnswers([])
}
In this manner, b
will be defined as desired for the setQuestionsBlok
call.