Skip to content

Commit

Permalink
Merge pull request #29 from linasmnew/cleanup-formatting
Browse files Browse the repository at this point in the history
cleanup
  • Loading branch information
linasmnew authored Apr 25, 2020
2 parents ccd32e4 + 12c64d5 commit f6cbfe7
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 62 deletions.
4 changes: 3 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ module.exports = {
],
rules: {
indent: ['error', 4],
'react/prop-types': [0]
'react/prop-types': [0],
'react/jsx-curly-spacing': ['error', 'always'],
'arrow-parens': ['error', 'as-needed']
}
};
119 changes: 72 additions & 47 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import React, { Component } from 'react'
import throttle from 'lodash.throttle'

function registerListener (event, fn) {
const registerListener = (event, fn) => {
if (window.addEventListener) {
window.addEventListener(event, fn)
} else {
window.attachEvent('on' + event, fn)
}
}

function isInViewport (el) {
if (!el) return false
const rect = el.getBoundingClientRect()
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.left <= (window.innerWidth || document.documentElement.clientWidth)
)
const isInViewport = el => {
if (el) {
const rect = el.getBoundingClientRect()

return rect.top >= 0 &&
rect.left >= 0 &&
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.left <= (window.innerWidth || document.documentElement.clientWidth)
}
}

const fadeIn = `
Expand All @@ -31,11 +31,9 @@ const fadeIn = `
class GracefulImage extends Component {
constructor (props) {
super(props)
this._isMounted = false

// store a reference to the throttled function
this._isMounted = false
this.throttledFunction = throttle(this.lazyLoad, 150)

this.state = {
loaded: false,
retryDelay: this.props.retry.delay,
Expand All @@ -52,6 +50,7 @@ class GracefulImage extends Component {

if (!exists.length) {
const styleElement = document.createElement('style')

styleElement.setAttribute('data-gracefulimage', 'exists')
document.head.appendChild(styleElement)
styleElement.sheet.insertRule(fadeIn, styleElement.sheet.cssRules.length)
Expand All @@ -72,6 +71,7 @@ class GracefulImage extends Component {
*/
loadImage () {
const image = new Image()

image.onload = () => {
this.setLoaded()
}
Expand Down Expand Up @@ -102,7 +102,7 @@ class GracefulImage extends Component {

// if user wants to lazy load
if (!this.props.noLazyLoad) {
// check if already within viewport to avoid attaching listeners
// check if already within viewport to avoid attaching listeners
if (isInViewport(this.placeholderImage)) {
this.loadImage()
} else {
Expand Down Expand Up @@ -130,6 +130,7 @@ class GracefulImage extends Component {
*/
componentWillUnmount () {
this._isMounted = false

if (this.timeout) {
window.clearTimeout(this.timeout)
}
Expand All @@ -141,42 +142,51 @@ class GracefulImage extends Component {
following the default / provided retry algorithm
*/
handleImageRetries (image) {
const {
src,
retry: {
count,
delay,
accumulate
},
onError
} = this.props
const {
retryCount,
retryDelay
} = this.state
// if we are not mounted anymore, we do not care, and we can bail
if (!this._isMounted) {
return
}
if (!this._isMounted) return

this.setState({ loaded: false }, () => {
if (this.state.retryCount <= this.props.retry.count) {
if (retryCount <= count) {
this.timeout = setTimeout(() => {
// if we are not mounted anymore, we do not care, and we can bail
if (!this._isMounted) {
return
}
if (!this._isMounted) return

// re-attempt fetching the image
image.src = this.props.src
image.src = src

// update count and delay
this.setState(prevState => {
let updateDelay
let updatedRetryDelay

if (this.props.retry.accumulate === 'multiply') {
updateDelay = prevState.retryDelay * this.props.retry.delay
} else if (this.props.retry.accumulate === 'add') {
updateDelay = prevState.retryDelay + this.props.retry.delay
if (accumulate === 'multiply') {
updatedRetryDelay = prevState.retryDelay * delay
} else if (accumulate === 'add') {
updatedRetryDelay = prevState.retryDelay + delay
} else {
updateDelay = this.props.retry.delay
updatedRetryDelay = delay
}

return {
retryDelay: updateDelay,
retryDelay: updatedRetryDelay,
retryCount: prevState.retryCount + 1
}
})
}, this.state.retryDelay * 1000)
}, retryDelay * 1000)
} else {
this.props.onError()
onError()
}
})
}
Expand All @@ -187,31 +197,46 @@ class GracefulImage extends Component {
- Else render the placeholder
*/
render () {
if (!this.state.loaded && this.props.noPlaceholder) { return null }

const src = this.state.loaded ? this.props.src : this.state.placeholder
const style = this.state.loaded
const {
src,
noPlaceholder,
placeholderColor,
srcSet,
className,
width,
height,
style,
alt
} = this.props
const {
loaded,
placeholder
} = this.state
const imageSrc = loaded ? src : placeholder
const imageStyle = loaded
? {
animationName: 'gracefulimage',
animationDuration: '0.3s',
animationIterationCount: 1,
animationTimingFunction: 'ease-in'
}
: { background: this.props.placeholderColor }
: { background: placeholderColor }

if (!loaded && noPlaceholder) return null

return (
<img
src={src}
srcSet={this.props.srcSet}
className={this.props.className}
width={this.props.width}
height={this.props.height}
style={{
...style,
...this.props.style
}}
alt={this.props.alt}
ref={ref => (this.placeholderImage = ref)}
src={ imageSrc }
srcSet={ srcSet }
className={ className }
width={ width }
height={ height }
style={ {
...imageStyle,
...style
} }
alt={ alt }
ref={ ref => (this.placeholderImage = ref) }
/>
)
}
Expand Down
28 changes: 14 additions & 14 deletions tests/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('react-graceful-image client', () => {
height: '150'
}
const div = document.createElement('div')
ReactDOM.render(<GracefulImage {...props} />, div)
ReactDOM.render(<GracefulImage { ...props } />, div)
})

it('should render SVG placeholder when image has not loaded', () => {
Expand All @@ -23,7 +23,7 @@ describe('react-graceful-image client', () => {
width: '150',
height: '150'
}
const mountWrapper = mount(<GracefulImage {...props} />)
const mountWrapper = mount(<GracefulImage { ...props } />)

expect(mountWrapper.find('img').length).toBe(1)
expect(mountWrapper.find('img').prop('src')).toEqual('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7')
Expand All @@ -37,7 +37,7 @@ describe('react-graceful-image client', () => {
width: '150',
height: '150'
}
const mountWrapper = mount(<GracefulImage {...props} />)
const mountWrapper = mount(<GracefulImage { ...props } />)
mountWrapper.setState({ loaded: true })

expect(mountWrapper.find('img').length).toBe(1)
Expand All @@ -53,7 +53,7 @@ describe('react-graceful-image client', () => {
height: '150',
noPlaceholder: true
}
const mountWrapper = mount(<GracefulImage {...props} />)
const mountWrapper = mount(<GracefulImage { ...props } />)
expect(mountWrapper.find('img').length).toBe(0)

mountWrapper.setState({ loaded: true })
Expand All @@ -67,7 +67,7 @@ describe('react-graceful-image client', () => {
height: '150',
placeholderColor: '#aaa'
}
const mountWrapper = mount(<GracefulImage {...props} />)
const mountWrapper = mount(<GracefulImage { ...props } />)

expect(mountWrapper.find('img').prop('style')).toHaveProperty(
'background',
Expand All @@ -82,7 +82,7 @@ describe('react-graceful-image client', () => {
height: '150',
alt: 'hello world'
}
const mountWrapper = mount(<GracefulImage {...props} />)
const mountWrapper = mount(<GracefulImage { ...props } />)
expect(mountWrapper.find('img').prop('alt')).toEqual(props.alt)

mountWrapper.setState({ loaded: true })
Expand All @@ -96,7 +96,7 @@ describe('react-graceful-image client', () => {
height: '150',
className: 'graceful_image'
}
const mountWrapper = mount(<GracefulImage {...props} />)
const mountWrapper = mount(<GracefulImage { ...props } />)
expect(mountWrapper.find('img').prop('className')).toEqual(
props.className
)
Expand All @@ -114,7 +114,7 @@ describe('react-graceful-image client', () => {
height: '150'
}
const spy = jest.spyOn(window, 'addEventListener')
shallow(<GracefulImage {...props} />)
shallow(<GracefulImage { ...props } />)

expect(spy).toHaveBeenCalled()
expect(spy).toHaveBeenCalledTimes(4)
Expand All @@ -133,13 +133,13 @@ describe('react-graceful-image client', () => {
noLazyLoad: true
}
const spy = jest.spyOn(window, 'addEventListener')
shallow(<GracefulImage {...props} />)
shallow(<GracefulImage { ...props } />)

expect(spy).toHaveBeenCalledTimes(0)
spy.mockClear()
})

it('should fire onLoad prop when image loads', (done) => {
it('should fire onLoad prop when image loads', done => {
global.Image = class {
constructor () {
setTimeout(() => {
Expand All @@ -155,11 +155,11 @@ describe('react-graceful-image client', () => {
noLazyLoad: true,
onLoad
}
const mountWrapper = mount(<GracefulImage {...props} />)
const mountWrapper = mount(<GracefulImage { ...props } />)
mountWrapper.setState({ loaded: true })
})

it('should fire onError prop when image fails to load after reaching the retry limit', (done) => {
it('should fire onError prop when image fails to load after reaching the retry limit', done => {
global.Image = class {
constructor () {
setTimeout(() => {
Expand All @@ -175,7 +175,7 @@ describe('react-graceful-image client', () => {
retry: { count: 0, delay: 1 },
onError
}
const mountWrapper = mount(<GracefulImage {...props} />)
mountWrapper.setState({ loaded: true })
const mountWrapper = mount(<GracefulImage { ...props } />)
mountWrapper.setState({ loaded: false })
})
})

0 comments on commit f6cbfe7

Please sign in to comment.