Reputation: 839
I'm working of Gallery feature of my website where I wanna show all images to client. I have successfully fetched images from server to client end in the form of blob. Images also display but on second attempt. I need to visit that gallery page for first time for fetching images then I need to visit any page and re-visit that gallery page for displaying those images.
Here is my code. Kindly let me know where I'm making mistake.
Code of main Gallery Component
constructor(props) {
super(props);
this.state = {
eventDetail: [],
images: [],
imagesInBlob: [],
url: ''
}
this.getAllEventsData = this.getAllEventsData.bind(this);
}
componentDidMount() {
this.getAllEventsData();
}
getAllEventsData() {
axios({
method: 'POST',
url: '/api/Account/GetAllEventsData',
contentType: 'application/json',
data: {},
}).then(function (response) {
console.log(response);
this.setState({
eventDetail: response.data
});
this.getAllImages();
}.bind(this))
}
getAllImages() {
axios({
method: 'POST',
url: '/api/Account/GetAllEventImages',
contentType: 'application/json',
data: {},
}).then(function (response) {
console.log(response);
this.setState({
images: response.data
});
this.getImageBlobs();
}.bind(this))
}
getImageBlobs() {
console.log("Image Objects:", this.state.images);
for (var i = 0; i < this.state.images.length; i++) {
this.fetchEventImage(this.state.images[i].image_path);
}
this.setState({
imagesInBlob: imageArr
});
console.log("Images in Blob:", this.state.imagesInBlob);
}
fetchEventImage(imagePath) {
var path = {
ImagePath: imagePath
}
axios({
method: 'POST',
url: '/api/ImageFetch/FetchEventImages',
responseType: 'blob',// important
headers: {
'Content-Type': 'application/json'
},
data: path
}).then(function (response) {
var re = /(?:\.([^.]+))?$/;
const url = window.URL.createObjectURL(new Blob([response.data]));
imageArr[img_arr_cnt++] = url;
console.log("URL: ", url);
}).catch(error => {
console.log("Status:", error.response.status);
console.log("Data:", error.response.data);
});
}
handleImageDisplay() {
var imgTag = "<img src=" + this.state.imagesInBlob[0] + '" />';
return imgTag;
}
render() {
return (
<>
<section id="single-project" className="section">
<div className="container row justify-content-center">
<div className="col-lg-12">
<div className="row justify-content-center">
<div className="col-lg-6 project-info">
<h3>Meeting on 17th May 2019</h3>
<DisplayComp propName={this.state.imagesInBlob[0]} />
<img src={this.state.imagesInBlob[0]} />
</div>
</div>
</div>
</div>
</section >
</>
);
}
DisplayComp component code
constructor(props){
super(props);
}
render(){
return (
<img src={this.props.propName} alt="image"/>
);
}
Please let me know where I'm making mistake and how can I display it on client end?
Upvotes: 0
Views: 1547
Reputation: 1938
The issue is with fetchEventImage
. You are not setting state, no this.setState
. That is why your component does not rerenders. Try Promise.all.
getImageBlobs() {
console.log("Image Objects:", this.state.images);
const promises
for (var i = 0; i < this.state.images.length; i++) {
promises.push(this.fetchEventImage(this.state.images[i].image_path));
}
Promises.all(promises).then(imagesInBlob => {
this.setState({
imagesInBlob
});
})
}
fetchEventImage(imagePath) {
var path = {
ImagePath: imagePath
}
return axios({
method: 'POST',
url: '/api/ImageFetch/FetchEventImages',
responseType: 'blob',// importaqnt
headers: {
'Content-Type': 'application/json'
},
data: path
}).then(function (response) {
var re = /(?:\.([^.]+))?$/;
const url = window.URL.createObjectURL(new Blob([response.data]));
return url
console.log("URL: ", url);
}).catch(error => {
console.log("Status:", error.response.status);
console.log("Data:", error.response.data);
});
}
Sorry for any style issues, I answered on my phone
Upvotes: 0
Reputation: 1737
There's a lot going on in your code. You've some problems with asynchronous calls and also not all functions are bound to this
. I would suggest to convert your code to async/await to make it more readable and use named functions, because they are automatically bound to this
.
getAllEventsData = async () => {
const response = await axios({
method: 'POST',
url: '/api/Account/GetAllEventsData',
contentType: 'application/json',
data: {},
})
console.log(response);
this.setState({
eventDetail: response.data
});
this.getAllImages()
}
In getAllImages
it's neccessary to wait for setState
to be finished, because getImageBlobs
is using the state value and setState
is asynchronous.
getAllImages = async () => {
const response = await axios({
method: 'POST',
url: '/api/Account/GetAllEventImages',
contentType: 'application/json',
data: {},
})
console.log(response);
await this.setState({
images: response.data
});
this.getImageBlobs();
}
In getImageBlobs
there is a loop over a asynchronous function. So you need to wait till all calls are finished. Promise.all
will help here. Also imageArr
is some magically created global variable which is bad practise. Better return the value from fetchEventImage
and collect it in a local array. I replaced the for-loop with a map, which basically does the same, but looks cooler and cleaner and returns an array with all the Blob-URLs as Promise
. Also destructuring images
from this.state
helps cleaning up the code.
getImageBlobs = async () => {
const { images } = this.state
console.log("Image Objects:", images);
const imageArr = await Promise.all(
images.map(image => this.fetchEventImage(image.image_path))
this.setState({
imagesInBlob: imageArr
});
console.log("Images in Blob:", this.state.imagesInBlob);
}
Also in fetchEventImage
async/await looks cleaner and with try/catch you can do the same for error handling. As stated, this function will now return the created Blob-URL.
fetchEventImage = async (imagePath) => {
var path = {
ImagePath: imagePath
}
try {
const response = await axios({
method: 'POST',
url: '/api/ImageFetch/FetchEventImages',
responseType: 'blob',// important
headers: {
'Content-Type': 'application/json'
},
data: path
})
const url = window.URL.createObjectURL(new Blob([response.data]));
console.log("URL: ", url);
return url
} catch(error) {
console.log("Status:", error.response.status);
console.log("Data:", error.response.data);
}
}
I haven't tested the refactored code. Maybe there are some minor mistakes, but I think in general it should work.
Upvotes: 2