I'm trying to push new data to my posts array and display it on the client with DOM manipulation. The 1st two elements get displayed as expected but the 3rd element is not getting displayed while I'm using the async/await keyword
const posts = [
{
title: 'Post One',
body: 'This is post one'
},
{
title: 'Post Two',
body: 'This is post two'
}
];
const getPosts = () => {
setTimeout(() => {
let output = "";
posts.forEach((post, index) => {
output +=
`<ul>
<li>${post.title}</li>
</ul>`
})
document.getElementById('heading').innerHTML = output;
}, 1000);
}
const createPosts = (newPost) => {
setTimeout(() => {
posts.push(newPost);
}, 2000)
}
const newPost = async () => {
try{
await createPosts({title: 'Post Three', body: 'This is post three'});
getPosts();
}
catch{err => console.log(err)}
}
newPost();
createPosts() needs to return a Promise that's resolved after the timeout, so you can await it.
const createPosts = newPost =>
new Promise(resolve => setTimeout(() => {
posts.push(newPost);
resolve();
}), 2000));
Related
I have a function that receives data, I use an asynchronous promise to get a link to the document item.poster = await Promise.all(promises), then the data does not have time to be added to the array and I get an empty array. But if I remove the function where I get the link to the document, then everything works fine. In debug mode, I can see all the data fine, but why am I getting an empty array?
async FetchData({ state, commit }, to) {
try {
const q = query(collection(db, to));
await onSnapshot(q, (querySnapshot) => {
let data = [];
querySnapshot.forEach(async (doc) => {
let promises = [];
let item = {
id: doc.id,
name: doc.data().name,
slug: doc.data().slug,
country: doc.data().country,
duration: doc.data().duration,
year: doc.data().year,
video: doc.data().video,
genres: doc.data().genres,
actors: doc.data().actors,
};
if (to === "films") {
const starsRef = ref(storage, `images/${doc.id}/poster.png`);
promises.push(getDownloadURL(starsRef));
item.poster = await Promise.all(promises);
}
data.push(item);
});
commit("setData", { data, to });
});
} catch (err) {
console.error(err);
} }
forEach and async do not work nice together, forEach is not awaitable. But the solution is simple, .map and Promise.all():
// async not really needed
async FetchData({ state, commit }, to) {
const q = query(collection(db, to));
// TODO: Call the unsubscribeFn method in order to stop
// onSnapshot callback executions (when needed)
const unsubscribeFn = onSnapshot(q, (querySnapshot) => {
const allPromises = querySnapshot.docs.map(async (doc) => {
const docData = doc.data();
let item = {
id: doc.id,
name: docData.name,
slug: docData.slug,
country: docData.country,
duration: docData.duration,
year: docData.year,
video: docData.video,
genres: docData.genres,
actors: docData.actors
};
// Or you can use
// let item = { id: doc.id, ...docData };
if (to === "films") {
const starsRef = ref(storage, `images/${doc.id}/poster.png`);
item.poster = await getDownloadURL(starsRef);
}
return item;
});
Promise.all(allPromises)
.then((data) => commit("setData", { data, to }))
.catch(console.error);
});
}
Hi so I'm trying to grab some json from an api and then populate a table, pretty simple stuff.
What's happening is that I can see the "tableData" state being updated as each new row comes in, I'm also logging every time "tableData" is updated, yet maybe .5 seconds after its all done my "tableData" is empty again (check console screenshots)
const [bigChartData, setbigChartData] = React.useState("data1");
const [tableData, setTableData] = React.useState([]);
const setBgChartData = (name) => {
setbigChartData(name);
};
const getData = () => {
axios.get("URL")
.then(res => {
const data = res.data.items.forEach(item => {
setTableData(oldData => [...oldData, {
data: [
{ text: item.title },
{ text: "asd" + item.url },
{ text: "some links..." }
]
}]);
});
})
.catch(err => console.log(err));
setTimeout(function () {
console.log(tableData);
}, 3000);
}
useEffect(() => {
getData();
}, []);
useEffect(() => {
console.log("Table data updated:");
console.log(tableData);
}, [tableData]);
I think you should not iterate through each row inside getData() method instead try following code
const getData = () => {
axios.get("URL")
.then(res => {
const data = res.data.items.map(item => {
return{
data: [
{ text: item.title },
{ text: "asd" + item.url },
{ text: "some links..." }
]
};
});
setTableData(data)
}).catch(err => console.log(err));
}
or if you have already some data in tableData then
setTableData([...tableData, data])
I was solving a problem on a platform, but not getting how to do it?Can anyone help me out for this?
Problem Description
You are given the following API -
GET /api/comments
This will return a list of all comments. A comment object contains the following information
userId - ID of the user who commented
data - comment data
Given a userId, return an Array of comment data of all the comments by the given user.
Note
Apart from .json(), don’t use any other methods on the response object returned from fetch() call. This can cause your tests to fail.
Input - userId - the user id whose comment is to be returned.
Output - A list of comments by the given user id
Sample input 1 -
userId = 1
Sample API response
comments = [
{
'userId': '1',
"data": 'This looks slick!'
},
{
'userId': '2',
"data": 'I think this can be improved.'
},
{
'userId': '1',
"data": 'What kind of improvement?'
}]
Sample output 1 - ['This looks slick!', 'What kind of improvement?']
Below code that we have to complete
// TODO - Implement getCommentsByUserId() function
async function getCommentsByUserId(userId)
{
let v=await fetch(`/api/comments/${userId}`,{})
.then(response=>)
}
// ----------- Don't modify -----------
const mockFetch = (url, responseData) => {
const mockJsonPromise = Promise.resolve(responseData);
const mockFetchPromise = (callUrl) => {
if (url === callUrl) {
return Promise.resolve({
json: () => mockJsonPromise
});
} else {
return Promise.reject('404: No such url')
}
}
global.fetch = mockFetchPromise;
}
const successResponse = [
{
'userId': '1',
"data": 'This looks slick!'
},
{
'userId': '2',
"data": 'I think this can be improved.'
},
{
'userId': '1',
"data": 'What kind of improvement?'
}];
mockFetch('/api/comments', successResponse);
module.exports = getCommentsByUserId;
// ----------- Don't modify -----------
getCommentsByUserId("1").then((res) => {
console.log(res);
});
Use Array.prototype.filter:
let v = await fetch(`/api/comments/${userId}`,{})
.then(response=> response.json())
.then(comments => comments.filter(comment => comment.userId === userId))
You are lacking some knowledge on how async/await works. For filtering, as Alan has said, just use Array.prototype.filter.
When calling fetch, it returns a Promise. If you await fetch(...), the code will wait till fetch is finished, and returns the response of that API call.
async functions always returns a Promise (unless called with await). However, when writing the return statement in async functions, you must return a normal value.
async function getCommentsByUserId(userId)
{
let response = await fetch(`/api/comments/${userId}`,{});
let comments = response.json();
return comments.filter(comment => comment.userId === userId);
}
Either that, or using a normal function.
function getCommentsByUserId(userId)
{
return fetch(`/api/comments/${userId}`,{})
.then(res => res.json())
.then(comments => comments.filter(comment => comment.userId === userId));
}
Your test codes has many problems as well:
mockFetch('/api/comments', successResponse);: Your test code is mocking calling for the url "/api/comments/1", while you are mocking the API call for "/api/comments"
json: () => mockJsonPromise: The Response.json() functions is expected to return an actual value, and not a promise.
Here is my fixed version.
const mockFetch = (url, responseData) => {
return (callUrl) => {
if (url === callUrl) {
return Promise.resolve({
json: () => (responseData)
});
} else {
return Promise.reject('404: No such url')
}
};
}
const successResponse = [
{
'userId': '1',
"data": 'This looks slick!'
},
{
'userId': '2',
"data": 'I think this can be improved.'
},
{
'userId': '1',
"data": 'What kind of improvement?'
}];
global.fetch = mockFetch('/api/comments/1', successResponse);
async function getCommentsByUserId(userId) {
let response = await fetch(`/api/comments/${userId}`, {});
let comments = response.json();
return comments.filter(comment => comment.userId === userId);
}
getCommentsByUserId("1").then((res) => {
console.log(res);
});
I have made a few changes, now it's working fine but still, it doesn't clear any test cases.
However, it returns the same output as required.
// TODO - Implement getCommentsByUserId() function
async function getCommentsByUserId(userId) {
try{
let response = await fetch(`/api/comments`, {});
let comments = response.json();
comments = comments.filter(comment => comment.userId === userId);
a=[]
for(i of comments){
a.push(i.data)
}
return a;
}
catch{
return('404: No such url')
}
}
// ----------- Don't modify -----------
const mockFetch = (url, responseData) => {
const mockJsonPromise = Promise.resolve(responseData);
const mockFetchPromise = (callUrl) => {
if (url === callUrl) {
return Promise.resolve({
json: () => (responseData)
});
} else {
return Promise.reject('404: No such url')
}
}
global.fetch = mockFetchPromise;
}
const successResponse = [
{
'userId': '1',
"data": 'This looks slick!'
},
{
'userId': '2',
"data": 'I think this can be improved.'
},
{
'userId': '1',
"data": 'What kind of improvement?'
}];
mockFetch('/api/comments', successResponse);
module.exports = getCommentsByUserId;
// ----------- Don't modify -----------
getCommentsByUserId("1").then((res) => {
console.log(res);
});
I am successfully batch uploading images to firebase, but for some reason, my data is not being uploaded afterwards.
I can confirm though, it does work perfectly ONLY on a fresh build for the first time? Super weird.
I am not sure what is going wrong as I am able to receive the urls fine after the fact.
Here is my function:
onUploadImages = () => {
let photo =
Platform.OS === 'ios'
? this.state.images.map(img => img.uri.replace('file://', ''))
: this.state.images.map(img => img.uri);
Promise.all(
photo.map((image, index) => {
const sessionId = new Date().getTime();
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
let uploadBlob = null;
let mime = 'image/jpg';
const imageRef = firebase
.storage()
.ref('brandProducts/')
.child(`${this.props.userData.uid}`)
.child(`${sessionId}-${index}`);
return fs
.readFile(image, 'base64')
.then(data => {
return Blob.build(data, {
type: `${mime};BASE64`,
});
})
.then(blob => {
uploadBlob = blob;
return imageRef.put(blob, {contentType: mime});
})
.then(() => {
uploadBlob.close();
return imageRef.getDownloadURL();
});
}),
)
.then(results => {
//results is, here, [ urlFromFirst, urlFronSecond, ...]
const urls = {...this.state.urls};
results.forEach((r, i) => (urls[i] = r));
const postObj = {
...this.state.postObj,
urls,
};
//THIS WONT RUN (BUT I AM ABLE TO LOG PROPER postObj) here
return firebase
.firestore()
.collection('brandProducts')
.add(postObj);
})
.then(docRef => {
Actions.categories();
console.log('Document written with ID: ', docRef.id);
})
.catch(error => {
console.error(error);
});
};
Here is my postObj:
postObj: {
title: 'A Title',
price: 20,
description: 'Some text here',
webLink: 'a url as a string',
user: 'Username',
urls: {
'0': 'downloadUrl1',
'1': 'downloadUrl2',
'2': 'downloadUrl3',
}
},
I would appreciate any help i can get figuring out where this is going wrong. Cheers!
I am trying to fetch and map an array with 350 object's elements. I decided to use Hook and useEffect, to re render my dataTable component since mapping is done. Unfortunately, the whole process takes enormous amount of time, and it makes page unresponsive. After 1-2 minutes, table shows up and after few seconds it disappears. After that page is still unresponsive. Could someone explain why it happens, and give me some workaround? I would be grateful.
Code below:
const Employees = (props) => {
const [developers, setDevelopers] = useState([]);
useEffect(() => {
fetchData();
});
const columns = [
{
name: "Emloyee",
selector: "name",
sortable: true,
},
{
name: "Team ",
selector: "team",
sortable: true,
},
{
name: "Email ",
selector: "email",
sortable: true,
},
];
const fetchData = () => {
axios.get("http://localhost:3128/employees", {
headers: {
'Access-Control-Allow-Origin': '*',
}
})
.then((response) => {
mapData(response.data.developers);
console.log("I am here!");
})
.catch((e) => console.log(e));
};
const mapData = (jsonData) => {
jsonData.forEach((x) => {
let newDeveloper = {
name: x.userId,
team: x.team,
email: x.userId + "#mail.com",
};
setDevelopers((developers) => [...developers, newDeveloper]);
});
};
return <DataTable title="Employees" columns={columns} data={developers}/>;
};
useEffect without dependency array will run on every render, so in your case, you are stuck in an infinite loop which cause page to become unresponsive
solution:
const fetchData = useCallback(() => {
axios.get("http://localhost:3128/employees", {
headers: {
'Access-Control-Allow-Origin': '*',
}
})
.then((response) => {
mapData(response.data.developers);
console.log("I am here!");
})
.catch((e) => console.log(e));
},[]);
const mapData = useCallback((jsonData) => {
jsonData.forEach((x) => {
let newDeveloper = {
name: x.userId,
team: x.team,
email: x.userId + "#kuehne-nagel.com",
};
setDevelopers((developers) => [...developers, newDeveloper]);
});
},[]);
useEffect(() => {
fetchData();
},[fetchData]); // pass dependency array here in useEffect
Thanks to #DrewReese and #SarthakAggarwal , I've got a solution:
const Employees = (props) => {
const [developers, setDevelopers] = useState([]);
const columns = [
{
name: "Emloyee",
selector: "name",
sortable: true,
},
{
name: "Team ",
selector: "team",
sortable: true,
},
{
name: "Email ",
selector: "email",
sortable: true,
},
];
const fetchData = useCallback(() => {
axios.get("http://localhost:3128/employees", {
headers: {
'Access-Control-Allow-Origin': '*',
}
})
.then((response) => {
mapData(response.data.developers);
console.log("I am here!");
})
.catch((e) => console.log(e));
}, []);
const mapData = (jsonData) => {
let table = [];
jsonData.forEach((x) => {
let newDeveloper = {
name: x.userId,
team: x.team,
email: x.userId + "#mail.com",
};
table = [...table,newDeveloper];
//setDevelopers((developers) => [...developers, newDeveloper]);
});
setDevelopers((developers) => table);
};
useEffect(() => {
fetchData();
}, [fetchData]);
return <DataTable title="Employees" columns={columns} data={developers}/>;
};
Thanks a lot !