Reputation: 855
I have a lifecycle method componentDidMount that calls upon a recursive async method and I want the recursive function to return a promise after all the data has been fetched.
async componentDidMount() {
let response = await fetch(`${STORY_URL}${this.props.match.params.id}.json`);
let result = await response.json();
totalComments = result.descendants;
await this.fetchComments(result.kids, MARGIN);
this.setState({
by: result.by,
time: calculateTimeDifference(result.time)
});
}
and the function being called is
async fetchComments(comment, margin) {
return new Promise((resolve, reject) => {
comment.map(async commentId => {
let response = await fetch(`${STORY_URL}${commentId}.json`);
let result = await response.json();
comments.push({
by: result.by,
margin: margin
});
if (comments.length === totalComments + 1) resolve();
if (result.kids !== undefined) this.fetchComments(result.kids, margin * 2);
});
});
}
but the resolve method is not returning back to the componentDidMount before the setState. I checked by console logging. I don't know what I am doing wrong
Upvotes: 3
Views: 638
Reputation: 138537
You are overcomplicating things. Use Promise.all
:
async fetchComments(comments, margin) {
// Collect all the results here, otgerwise we would have to flatMap the promises which is more complicated
const result = [];
// Make sure that all comments were processed before returning
await Promise.all( comments.map(async commentId => {
const response = await fetch(`${STORY_URL}${commentId}.json`);
const { kids, by } = await response.json();
if(kids) {
// Get all children and append them to the results, right after the children
const children = await fetchComments(kids, margin * 2);
result.push({ by, margin }, ...children);
} else {
// Otherwise just append this node
result.push({ by, margin });
}
}));
return result;
}
If the order matters, you have to flatten the result of Promise.all
:
async fetchComments(comments, margin) {
const result = await Promise.all(comments.map( async commentID => {
const response = await fetch(STORY_URL + commentID + ".json");
const { by, kids } = await response.json();
const result = [{ by, margin }];
if(kids) result.push(... await fetchComments(kids, margin * 2));
return result;
}));
// Flatten the results
return [].concat(...result);
}
Upvotes: 3