Reputation: 5568
I want to do a basic if, else
operation inside my component, for that I need to return a [boolean] after checking if the image loaded correctly or not.
export const Suggest = (props) => {
function handleLoad(url) {
let image = new Image();
image.src = url;
image.onload = function() {
return false;
}
image.onerror = function() {
return true;
}
}
return (
<div>
{
props.state.suggestions.map((item, i) =>
<div key={i}>
<span>Boolean {i} = {handleLoad(item.image) ? 'True' : 'False'}</span>
</div>
)
}
</div>
)
}
Unfortunately calling the function handleLoad(item.image)
returns null
.
How should I fix this problem?
Upvotes: 1
Views: 2005
Reputation: 3107
The handleLoad
function does not return anything, and will return undefined
by default.
The onload
and onerror
are assigned new functions.
Since you're loading an image (an asynchronous operation), there is no way to return the result synchronously. You will need to use promises, e.g.
function handleLoad(url) {
return new Promise(function (resolve, reject) {
let image = new Image();
image.src = url;
image.onload = function() {
resolve();
}
image.onerror = function() {
reject(new Error('Image loading failed'));
}
});
}
Then, you can load your images on componentDidMount
, and use the then
callback to set your state accordingly:
// This is just a helper method to set the loaded
// flag and update the state for a given suggestion.
// Added it to avoid repeating ourselves.
setSuggestionLoaded = (suggestionIndex, isLoaded) => {
let suggestions = this.state.suggestions;
suggestions[suggestionIndex].loaded = isLoaded;
this.setState({ suggestions: suggestions });
}
componentDidMount() {
this.state.suggestions.map((suggestion, i) => {
handleLoad(suggestion)
.then(() => {
setSuggestionLoaded(i, true);
})
.catch((err) => {
setSuggestionLoaded(i, false);
}));
})
}
Then you can render your state, it will be updated when the loading operations finish or fail.
return (
<div>
{
props.state.suggestions.map((item, i) =>
<div key={i}>
<span>Boolean {i} = {item.loaded ? 'True' : 'False'}</span>
</div>
)
}
</div>
)
Another option to do this would be via plain old callbacks, e.g.:
function handleLoad(url, successCallback, errorCallback) {
let image = new Image();
image.src = url;
image.onload = function() {
if(successCallback) successCallback();
}
image.onerror = function() {
if(errorCallback) errorCallback(new Error('Image loading failed'));
}
}
componentDidMount() {
this.state.suggestions.map((suggestion, i) => {
handleLoad(suggestion,
() => {
setSuggestionLoaded(i, true);
},
(err) => {
setSuggestionLoaded(i, false);
}
);
})
}
But I'd personally recommend the promises approach. I'd go even further and recommend you to read about the new async / await
syntax which essentially is a pretty way to write promise-based asynchronous JavaScript.
Upvotes: 1