Last active
April 15, 2019 23:17
-
-
Save hartzis/9b23d09f2c98019ddcf452f6916f09aa to your computer and use it in GitHub Desktop.
react image component - utilizing recompose, handles errors
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component, PropTypes } from 'react'; | |
import { setPropTypes, withState, lifecycle, mapProps, compose } from 'recompose'; | |
export const ImageComponent = compose( | |
setPropTypes({ src: PropTypes.string.isRequired }), | |
withState('imgState', 'updateImgState', ({ src }) => ({ origSrc: src, currentSrc: src })), | |
lifecycle({ | |
componentWillReceiveProps(nextProps) { | |
// if Image components src changes, make sure we update origSrc and currentSrc | |
if (nextProps.src !== nextProps.imgState.origSrc) { | |
nextProps.updateImgState({ origSrc: nextProps.src, currentSrc: nextProps.src }); | |
} | |
}, | |
}), | |
mapProps(({ imgState, updateImgState })=>{ | |
return { | |
src: imgState.currentSrc, | |
// img load error: spread origSrc, and update new currentSrc to the fallback image | |
onError: () => updateImgState((s) => ({ ...s, currentSrc: 'FALLBACK_IMG_SRC' })), | |
}; | |
}) | |
)(Image); | |
class Image extends Component { | |
constructor() { | |
super(); | |
this.assignImageRef = this.assignImageRef.bind(this); | |
} | |
componentDidMount() { | |
const { src } = this.props; | |
// if image hasn't completed loading, then let react handle error | |
if (!this._image.complete) return; | |
/* | |
* If an image has finished loading and has 'errored' (errored when naturalWidth === 0, or if svg check width) | |
* Then run the onError callback | |
* NOTE IF SVG: need to use width because firefox and IE assign naturalWidth from the svg elements width property, | |
* but some svgs don't have that specified | |
*/ | |
const isInvalidSvg = srcRepresentsSvgFile(src) && !this._image.width; | |
const imgFailedToLoad = this._image.naturalWidth === 0; | |
if (isInvalidSvg || imgFailedToLoad) { | |
this.props.onError(); | |
} | |
} | |
assignImageRef(r) { | |
this._image = r; | |
} | |
render() { | |
const { src, onError } = this.props; | |
return <img ref={ this.assignImageRef } src={ src } onError={ onError } />; | |
} | |
} | |
// checks for svg if last 4 characters === '.svg' | |
function srcRepresentsSvgFile(src) { | |
return src && /\.svg$/.test(src); | |
} |
updated to handle svg
- add regex for
svg
check - simplify check for
error
'ed images - use bound method for ref callback, avoids recreating anonymous function on every render
withState('imgState', 'updateImgState', ({ src }) => { origSrc: src, currentSrc: src }),
should be (line 14)
withState('imgState', 'updateImgState', ({ src }) => ({ origSrc: src, currentSrc: src })),
@bertho-zero thank you
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
associated blog post - http://www.hartzis.me/onError-image-component/
Recompose
v0.20.0 - Recompose: react functional utility belt