diff --git a/src/behaviors/Visibility/Visibility.js b/src/behaviors/Visibility/Visibility.js index 3c4d9c5882..eeab312af5 100644 --- a/src/behaviors/Visibility/Visibility.js +++ b/src/behaviors/Visibility/Visibility.js @@ -193,7 +193,7 @@ export default class Visibility extends Component { const { context, fireOnMount } = this.props - context.addEventListener('scroll', this.handleUpdate) + context.addEventListener('scroll', this.handleScroll) if (fireOnMount) this.handleUpdate() } @@ -201,7 +201,7 @@ export default class Visibility extends Component { if (!isBrowser) return const { context } = this.props - context.removeEventListener('scroll', this.handleUpdate) + context.removeEventListener('scroll', this.handleScroll) } execute = (callback, name) => { @@ -292,9 +292,18 @@ export default class Visibility extends Component { }) } + handleScroll = () => { + if (this.ticking) return + + this.ticking = true + requestAnimationFrame(this.handleUpdate) + } + handleRef = c => (this.ref = c) handleUpdate = () => { + this.ticking = false + const { offset } = this.props const { bottom, height, top, width } = this.ref.getBoundingClientRect() const [topOffset, bottomOffset] = normalizeOffset(offset) diff --git a/test/specs/behaviors/Visibility/Visibility-test.js b/test/specs/behaviors/Visibility/Visibility-test.js index 244d372f4d..6c2d68af21 100644 --- a/test/specs/behaviors/Visibility/Visibility-test.js +++ b/test/specs/behaviors/Visibility/Visibility-test.js @@ -96,29 +96,23 @@ const expectations = [{ describe('Visibility', () => { common.isConformant(Visibility) - beforeEach(() => { - wrapper = undefined + let requestAnimationFrame + + before(() => { + requestAnimationFrame = window.requestAnimationFrame + window.requestAnimationFrame = fn => fn() }) - afterEach(() => { - if (wrapper && wrapper.unmount) wrapper.unmount() + after(() => { + window.requestAnimationFrame = requestAnimationFrame }) - it('should use window as default scroll context', () => { - const onUpdate = sandbox.spy() - mount() - window.dispatchEvent(new Event('scroll')) - onUpdate.should.have.been.called() + beforeEach(() => { + wrapper = undefined }) - it('should set a scroll context', () => { - const div = document.createElement('div') - const onUpdate = sandbox.spy() - mount() - window.dispatchEvent(new Event('scroll')) - onUpdate.should.not.have.been.called() - div.dispatchEvent(new Event('scroll')) - onUpdate.should.have.been.called() + afterEach(() => { + if (wrapper && wrapper.unmount) wrapper.unmount() }) describe('calculations', () => { @@ -186,6 +180,28 @@ describe('Visibility', () => { }) }) + describe('context', () => { + it('should use window as default scroll context', () => { + const onUpdate = sandbox.spy() + mount() + + window.dispatchEvent(new Event('scroll')) + onUpdate.should.have.been.called() + }) + + it('should set a scroll context', () => { + const div = document.createElement('div') + const onUpdate = sandbox.spy() + mount() + + window.dispatchEvent(new Event('scroll')) + onUpdate.should.not.have.been.called() + + div.dispatchEvent(new Event('scroll')) + onUpdate.should.have.been.called() + }) + }) + describe('fireOnMount', () => { it('fires callbacks after mount', () => { const onUpdate = sandbox.spy()