I'm mapping through an array of items to generate images, but each time it sends my code into an infinite loop. Here's my code:
This is the mapping code:
let mySrc = this.state.imageUrl;
{myImages.map(image => {
this.getSrc(userId, image.id);
return(
<img src={mySrc}/>)
})}
This is the "getSrc" function:
getSrc = async (userId, image) => {
axios
.get(`http://mysiteeee.com/api/getimage/${userId}/photo/${image}`, {
auth: {
username: 'username',
password: 'password'
},
responseType: 'blob'
})
.then(res => {
let myUrl = URL.createObjectURL(res.data)
console.log(myUrl)
this.setState({
imageUrl: myUrl
})
})
.catch(err => console.log(err))
}
Whenever I go to the page, it shuffles through all the image URLs / images over and over forever. How do I only show the image URLs / images once? How do I stop shuffling through images infinitely?
Here's the entire component's code:
import React from 'react';
import axios from 'axios';
import HeaderTwo from './HeaderTwo';
class FullDescription extends React.Component {
constructor(props) {
super(props);
this.state = {
eventInfo: [],
imageUrl: [],
clicked: false,
}
}
componentDidMount = () => {
window.scrollTo(0,0);
this.props.state.images.map(image =>
this.getSrc(this.props.state.id, image.id))
// this.getSrc(this.props.state.id, this.props.state.images[1].id)
}
changeClicked = (userId) => {
if(this.state.clicked === false){
this.setState({
clicked: true
})
} else {
this.setState({
clicked: false
})
}
}
getSrc = async (userId, image) => {
axios
.get(`http://http://mysiteeee.com/api/getimage/${userId}/photo/${image}`, {
auth: {
username: 'username',
password: 'password'
},
responseType: 'blob'
})
.then(res => {
let myUrl = URL.createObjectURL(res.data)
this.state.imageUrl.push(myUrl)
// this.setState({
// imageUrl: myUrl
// })
})
.catch(err => console.log(err))
}
render() {
let item = this.props.state;
let date = new Date(item.date).toDateString();
let time = new Date(item.date).toLocaleTimeString();
let userId = this.props.state.id;
let myImages = this.state.imageUrl;
let checkMark = <button className='attend-button' onClick={() => this.changeClicked(userId)}>Attend Event</button>;
console.log(myImages)
if(this.state.clicked === true){
checkMark = <button className='attend-button' onClick={() => this.changeClicked(userId)}>✓ Attend Event</button>
} else {
checkMark = <button className='attend-button' onClick={() => this.changeClicked(userId)}>Attend Event</button>
}
return(
<div>
<HeaderTwo/>
<body id="full-description-page">
<div className='images-section'>
{myImages.map(mySrc => <img src={mySrc}/>)}
</div>
<div id='heading-strip'>
<img src={myImages} className='heading-image'/>
<div className='heading-info'>
<p className='date'>{date}<br/>{time}</p>
<p className='name'>{item.name}</p>
<p className='location'><b>Location:</b> <br/>{item.location.name}, {item.location.address}, {item.location.city}, {item.location.state}</p>
<div className='button-area'>
{checkMark}
</div>
</div>
</div>
<br/>
<p className='description'><b>Description:</b> {item.description}</p>
<br/><br/><br/><br/>
<p className='comments-header'><b>Comments:</b></p>
<div className='comments-section'>
{item.comments.map(comment =>
<div className='comments'>
<p>{comment.text}<br/><b>-{comment.from}</b></p>
</div>
)}
</div>
</body>
</div>
)
}
}
export default FullDescription;
The issue in the code is that you are calling getSrc
method inside the render method and updating the state
.
Whenever there is a change in state, React will call the render method.
In this case React call the render method and in the render method there is a state update, hence React call the render method again, and this process goes on forever.
Solution.
Remove the this.getSrc
from render method and call the getSrc
method in componentDidMount
lifecycle hook.
I made a small change in the map function as well.
Example.
let myImages = this.state.imageUrl;
{myImages.map(mySrc => <img src={mySrc}/>)}
componentDidMount() {
this.getSrc();
}