From 1e9e4a4fdf86b1a84a6a814bebb22f530b47350e Mon Sep 17 00:00:00 2001 From: Alexander Fedyashov Date: Tue, 19 Sep 2017 12:00:05 +0300 Subject: [PATCH 1/3] fix(Visibility): fire on window resize, fix behaviour of reverse calls --- src/behaviors/Visibility/Visibility.js | 175 +++++----- .../behaviors/Visibility/Visibility-test.js | 299 +++++++++++------- 2 files changed, 291 insertions(+), 183 deletions(-) diff --git a/src/behaviors/Visibility/Visibility.js b/src/behaviors/Visibility/Visibility.js index eeab312af5..5bb2c6e423 100644 --- a/src/behaviors/Visibility/Visibility.js +++ b/src/behaviors/Visibility/Visibility.js @@ -171,21 +171,27 @@ export default class Visibility extends Component { } calculations = { - topPassed: false, bottomPassed: false, - topVisible: false, bottomVisible: false, fits: false, passing: false, - onScreen: false, offScreen: false, + onScreen: false, + topPassed: false, + topVisible: false, } - firedCallbacks = [] + occurredCallbacks = [] + + // ---------------------------------------- + // Lifecycle + // ---------------------------------------- componentWillReceiveProps({ continuous, once }) { - const cleanOut = continuous !== this.props.continuous || once !== this.props.once - if (cleanOut) this.firedCallbacks = [] + const cleanHappened = continuous !== this.props.continuous || once !== this.props.once + + // Heads up! We should clean up array of happened callbacks, if values of these props are changed + if (cleanHappened) this.occurredCallbacks = [] } componentDidMount() { @@ -193,86 +199,48 @@ export default class Visibility extends Component { const { context, fireOnMount } = this.props - context.addEventListener('scroll', this.handleScroll) - if (fireOnMount) this.handleUpdate() + context.addEventListener('scroll', this.handleUpdate) + if (fireOnMount) this.update() } componentWillUnmount() { if (!isBrowser) return const { context } = this.props - context.removeEventListener('scroll', this.handleScroll) + context.removeEventListener('scroll', this.handleUpdate) } - execute = (callback, name) => { - const { continuous, once } = this.props + // ---------------------------------------- + // Callback handling + // ---------------------------------------- + execute(callback, name) { + const { continuous } = this.props if (!callback) return - // Reverse callbacks aren't fired continuously - if (this.calculations[name] === false) return - // Always fire callback if continuous = true - if (continuous) { - callback(null, { ...this.props, calculations: this.calculations }) - return - } + // Heads up! When `continuous` is true, callback will be fired always + if (!continuous && _.includes(this.occurredCallbacks, name)) return - // If once = true, fire callback only if it wasn't fired before - if (once) { - if (!_.includes(this.firedCallbacks, name)) { - this.firedCallbacks.push(name) - callback(null, { ...this.props, calculations: this.calculations }) - } - - return - } - - // Fire callback only if the value changed - if (this.calculations[name] !== this.oldCalculations[name]) { - callback(null, { ...this.props, calculations: this.calculations }) - } + callback(null, { ...this.props, calculations: this.calculations }) + this.occurredCallbacks.push(name) } - fireCallbacks() { - const { - onBottomPassed, - onBottomPassedReverse, - onBottomVisible, - onBottomVisibleReverse, - onPassing, - onPassingReverse, - onTopPassed, - onTopPassedReverse, - onTopVisible, - onTopVisibleReverse, - onOffScreen, - onOnScreen, - } = this.props - const callbacks = { - bottomPassed: onBottomPassed, - bottomVisible: onBottomVisible, - passing: onPassing, - offScreen: onOffScreen, - onScreen: onOnScreen, - topPassed: onTopPassed, - topVisible: onTopVisible, - } - const reverse = { - bottomPassed: onBottomPassedReverse, - bottomVisible: onBottomVisibleReverse, - passing: onPassingReverse, - topPassed: onTopPassedReverse, - topVisible: onTopVisibleReverse, - } + fire = ({ callback, name }, value, reverse = false) => { + const { continuous, once } = this.props - _.invoke(this.props, 'onUpdate', null, { ...this.props, calculations: this.calculations }) - this.fireOnPassed() + // Heads up! For the execution is required: + // - current value correspond to the fired direction + // - `continuous` is true or calculation values are different + const matchesDirection = this.calculations[value] !== reverse + const executionPossible = continuous || this.calculations[value] !== this.oldCalculations[value] - _.forEach(callbacks, (callback, name) => this.execute(callback, name)) - _.forEach(reverse, (callback, name) => this.execute(callback, name)) + if (matchesDirection && executionPossible) this.execute(callback, name) + + // Heads up! We should remove callback from the happened when it's not `once` + if (!once) this.occurredCallbacks = _.without(this.occurredCallbacks, name) } - fireOnPassed = () => { + fireOnPassed() { const { percentagePassed, pixelsPassed } = this.calculations const { onPassed } = this.props @@ -292,18 +260,64 @@ export default class Visibility extends Component { }) } - handleScroll = () => { + handleUpdate = () => { if (this.ticking) return this.ticking = true - requestAnimationFrame(this.handleUpdate) + requestAnimationFrame(this.update) } - handleRef = c => (this.ref = c) - - handleUpdate = () => { + update = () => { this.ticking = false + this.oldCalculations = this.calculations + this.calculations = this.computeCalculations() + + const { + onBottomPassed, + onBottomPassedReverse, + onBottomVisible, + onBottomVisibleReverse, + onPassing, + onPassingReverse, + onTopPassed, + onTopPassedReverse, + onTopVisible, + onTopVisibleReverse, + onOffScreen, + onOnScreen, + } = this.props + const forward = { + bottomPassed: { callback: onBottomPassed, name: 'onBottomPassed' }, + bottomVisible: { callback: onBottomVisible, name: 'onBottomVisible' }, + passing: { callback: onPassing, name: 'onPassing' }, + offScreen: { callback: onOffScreen, name: 'onOffScreen' }, + onScreen: { callback: onOnScreen, name: 'onOnScreen' }, + topPassed: { callback: onTopPassed, name: 'onTopPassed' }, + topVisible: { callback: onTopVisible, name: 'onTopVisible' }, + } + + const reverse = { + bottomPassed: { callback: onBottomPassedReverse, name: 'onBottomPassedReverse' }, + bottomVisible: { callback: onBottomVisibleReverse, name: 'onBottomVisibleReverse' }, + passing: { callback: onPassingReverse, name: 'onPassingReverse' }, + topPassed: { callback: onTopPassedReverse, name: 'onTopPassedReverse' }, + topVisible: { callback: onTopVisibleReverse, name: 'onTopVisibleReverse' }, + } + + _.invoke(this.props, 'onUpdate', null, { ...this.props, calculations: this.calculations }) + this.fireOnPassed() + + // Heads up! Reverse callbacks should be fired first + _.forEach(reverse, (data, value) => this.fire(data, value, true)) + _.forEach(forward, (data, value) => this.fire(data, value)) + } + + // ---------------------------------------- + // Helpers + // ---------------------------------------- + + computeCalculations() { const { offset } = this.props const { bottom, height, top, width } = this.ref.getBoundingClientRect() const [topOffset, bottomOffset] = normalizeOffset(offset) @@ -323,8 +337,7 @@ export default class Visibility extends Component { const onScreen = (topVisible || topPassed) && !bottomPassed const offScreen = !onScreen - this.oldCalculations = this.calculations - this.calculations = { + return { bottomPassed, bottomVisible, fits, @@ -338,10 +351,18 @@ export default class Visibility extends Component { topVisible, width, } - - this.fireCallbacks() } + // ---------------------------------------- + // Refs + // ---------------------------------------- + + handleRef = c => (this.ref = c) + + // ---------------------------------------- + // Render + // ---------------------------------------- + render() { const { children } = this.props const ElementType = getElementType(Visibility, this.props) diff --git a/test/specs/behaviors/Visibility/Visibility-test.js b/test/specs/behaviors/Visibility/Visibility-test.js index 6c2d68af21..ab6d70413d 100644 --- a/test/specs/behaviors/Visibility/Visibility-test.js +++ b/test/specs/behaviors/Visibility/Visibility-test.js @@ -3,7 +3,7 @@ import React from 'react' import Visibility from 'src/behaviors/Visibility' import * as common from 'test/specs/commonTests' -import { sandbox } from 'test/utils' +import { domEvent, sandbox } from 'test/utils' let wrapper @@ -26,38 +26,43 @@ const mockScroll = (top, bottom) => { } } - window.dispatchEvent(new Event('scroll')) + domEvent.scroll(window) } const expectations = [{ name: 'topPassed', - callback: 'onTopPassed', - true: [[-1, 100], [-100, -1]], - false: [[0, 100], [window.innerHeight + 100, window.innerHeight + 300]], + callbackName: 'onTopPassed', + reversible: true, + truthy: [[-1, 100], [-100, -1]], + falsy: [[0, 100], [window.innerHeight + 100, window.innerHeight + 300]], }, { name: 'bottomPassed', - callback: 'onBottomPassed', - true: [[-100, -1], [-100, -10]], - false: [[-10, 0], [-100, window.innerHeight]], + callbackName: 'onBottomPassed', + reversible: true, + truthy: [[-100, -1], [-100, -10]], + falsy: [[-10, 0], [-100, window.innerHeight]], }, { name: 'topVisible', - callback: 'onTopVisible', - true: [[0, 100], [window.innerHeight, window.innerHeight]], - false: [[-1, 100], [window.innerHeight + 1, window.innerHeight + 2]], + callbackName: 'onTopVisible', + reversible: true, + truthy: [[0, 100], [window.innerHeight, window.innerHeight]], + falsy: [[-1, 100], [window.innerHeight + 1, window.innerHeight + 2]], }, { name: 'bottomVisible', - callback: 'onBottomVisible', - true: [[-100, 0], [-100, window.innerHeight]], - false: [[-100, -1], [0, window.innerHeight + 1]], + callbackName: 'onBottomVisible', + reversible: true, + truthy: [[-100, 0], [-100, window.innerHeight]], + falsy: [[-100, -1], [0, window.innerHeight + 1]], }, { name: 'passing', - callback: 'onPassing', - true: [ + callbackName: 'onPassing', + reversible: true, + truthy: [ [-1, window.innerHeight + 1], [-1, window.innerHeight - 1], [-1, 0], ], - false: [ + falsy: [ [0, window.innerHeight], [1, window.innerHeight + 1], [1, window.innerHeight - 1], @@ -65,19 +70,19 @@ const expectations = [{ ], }, { name: 'onScreen', - callback: 'onOnScreen', - true: [ + callbackName: 'onOnScreen', + truthy: [ [0, window.innerHeight], [-1, window.innerHeight + 1], [-1, window.innerHeight], [0, window.innerHeight + 1], ], - false: [[-2, -1], [window.innerHeight + 1, window.innerHeight + 2]], + falsy: [[-2, -1], [window.innerHeight + 1, window.innerHeight + 2]], }, { name: 'offScreen', - callback: 'onOffScreen', - true: [[-2, -1], [window.innerHeight + 1, window.innerHeight + 2]], - false: [ + callbackName: 'onOffScreen', + truthy: [[-2, -1], [window.innerHeight + 1, window.innerHeight + 2]], + falsy: [ [0, window.innerHeight], [-1, window.innerHeight + 1], [-1, window.innerHeight], @@ -85,8 +90,8 @@ const expectations = [{ ], }, { name: 'fits', - true: [[0, window.innerHeight]], - false: [ + truthy: [[0, window.innerHeight]], + falsy: [ [-1, window.innerHeight + 1], [0, window.innerHeight + 1], [-1, window.innerHeight], @@ -116,67 +121,127 @@ describe('Visibility', () => { }) describe('calculations', () => { - expectations.forEach((expectation) => { - it(`calculates ${expectation.name}`, () => { - let calculations - const onUpdate = (e, props) => (calculations = props.calculations) + _.forEach(expectations, ({ falsy, name, truthy }) => { + it(`calculates ${name}`, () => { + const onUpdate = sandbox.spy() wrapperMount() - expectation.true.forEach(([top, bottom]) => { + _.forEach(truthy, ([top, bottom]) => { mockScroll(top, bottom) - calculations[expectation.name].should.equal(true, [top, bottom]) + onUpdate.should.have.been.calledWithMatch(null, { + calculations: { + [name]: true, + }, + }) }) - expectation.false.forEach(([top, bottom]) => { + _.forEach(falsy, ([top, bottom]) => { mockScroll(top, bottom) - calculations[expectation.name].should.equal(false, [top, bottom]) + onUpdate.should.have.been.calledWithMatch(null, { + calculations: { + [name]: false, + }, + }) }) }) + }) + }) + + describe('callbacks', () => { + _.forEach(_.filter(expectations, 'callbackName'), ({ callbackName, falsy, truthy }) => { + it(`fires ${callbackName}`, () => { + const callback = sandbox.spy() + const opts = { [callbackName]: callback } + wrapperMount() - if (expectation.callback) { - it(`fires ${expectation.name}`, () => { - const callback = sandbox.spy() - const opts = { [expectation.callback]: callback } - wrapperMount() + _.forEach(falsy, ([top, bottom]) => mockScroll(top, bottom)) + callback.should.not.have.been.called() - expectation.false.forEach(([top, bottom]) => mockScroll(top, bottom)) - callback.should.not.have.been.called() + _.forEach(truthy, ([top, bottom]) => mockScroll(top, bottom)) + callback.should.have.callCount(truthy.length) + }) - expectation.true.forEach(([top, bottom]) => mockScroll(top, bottom)) - callback.should.have.callCount(expectation.true.length) - }) + it(`fires ${callbackName} once`, () => { + const callback = sandbox.spy() + const falsyCond = _.first(falsy) + const truthyCond = _.first(truthy) + const opts = { [callbackName]: callback } + + wrapperMount() + + mockScroll(...truthyCond) + mockScroll(...falsyCond) + mockScroll(...truthyCond) + mockScroll(...falsyCond) + mockScroll(...truthyCond) + + callback.should.have.been.calledOnce() + }) + + it(`fires ${callbackName} when condition changes`, () => { + const callback = sandbox.spy() + const falsyCond = _.first(falsy) + const truthyCond = _.first(truthy) + const opts = { [callbackName]: callback } + wrapperMount() + + mockScroll(...truthyCond) + mockScroll(...falsyCond) + mockScroll(...truthyCond) + mockScroll(...truthyCond) + + callback.should.have.been.calledTwice() + }) + }) + + describe('reverse', () => { + _.forEach(_.filter(expectations, 'reversible'), ({ callbackName, falsy, truthy }) => { + it(`fires ${callbackName}Reverse once`, () => { + const falsyCond = _.first(falsy) + const truthyCond = _.first(truthy) + + const forward = sandbox.spy() + const reverse = sandbox.spy() + const opts = { [callbackName]: forward, [`${callbackName}Reverse`]: reverse } - it(`fires ${expectation.name} once`, () => { - const callback = sandbox.spy() - const falseCond = expectation.false[0] - const trueCond = expectation.true[0] - const opts = { [expectation.callback]: callback } wrapperMount() - mockScroll(...trueCond) - mockScroll(...falseCond) - mockScroll(...trueCond) - mockScroll(...falseCond) - mockScroll(...trueCond) + mockScroll(...truthyCond) + forward.should.have.been.calledOnce() + reverse.should.have.not.been.called() - callback.should.have.been.calledOnce() + mockScroll(...falsyCond) + forward.should.have.been.calledOnce() + reverse.should.have.been.calledOnce() }) - it(`fires ${expectation.name} when condition changes`, () => { - const callback = sandbox.spy() - const falseCond = expectation.false[0] - const trueCond = expectation.true[0] - const opts = { [expectation.callback]: callback } + it(`fires ${callbackName}Reverse when condition changes`, () => { + const falsyCond = _.first(falsy) + const truthyCond = _.first(truthy) + + const forward = sandbox.spy() + const reverse = sandbox.spy() + const opts = { [callbackName]: forward, [`${callbackName}Reverse`]: reverse } + wrapperMount() - mockScroll(...trueCond) - mockScroll(...falseCond) - mockScroll(...trueCond) - mockScroll(...trueCond) + mockScroll(...truthyCond) + forward.should.have.been.calledOnce() + reverse.should.have.not.been.called() + + mockScroll(...falsyCond) + forward.should.have.been.calledOnce() + reverse.should.have.been.calledOnce() - callback.should.have.been.calledTwice() + mockScroll(...truthyCond) + forward.should.have.been.calledTwice() + reverse.should.have.been.calledOnce() + + mockScroll(...falsyCond) + forward.should.have.been.calledTwice() + reverse.should.have.been.calledTwice() }) - } + }) }) }) @@ -185,19 +250,19 @@ describe('Visibility', () => { const onUpdate = sandbox.spy() mount() - window.dispatchEvent(new Event('scroll')) + domEvent.scroll(window) onUpdate.should.have.been.called() }) it('should set a scroll context', () => { const div = document.createElement('div') const onUpdate = sandbox.spy() - mount() + mount() - window.dispatchEvent(new Event('scroll')) + domEvent.scroll(window) onUpdate.should.not.have.been.called() - div.dispatchEvent(new Event('scroll')) + domEvent.scroll(div) onUpdate.should.have.been.called() }) }) @@ -218,34 +283,34 @@ describe('Visibility', () => { }) describe('offset', () => { - _.each(_.filter(expectations, 'callback'), (expectation) => { - it(`fires ${expectation.name} when offset is number`, () => { + _.forEach(_.filter(expectations, 'callbackName'), ({ callbackName, falsy, name, truthy }) => { + it(`fires ${name} when offset is number`, () => { const callback = sandbox.spy() - const opts = { [expectation.callback]: callback } + const opts = { [callbackName]: callback } const offset = 10 - const falseCond = _.map(expectation.false[0], value => value + offset) - const trueCond = _.map(expectation.true[0], value => value + offset) + const falsyCond = _.map(_.first(falsy), value => value + offset) + const truthyCond = _.map(_.first(truthy), value => value + offset) wrapperMount() - mockScroll(...trueCond) - mockScroll(...falseCond) + mockScroll(...truthyCond) + mockScroll(...falsyCond) callback.should.have.been.calledOnce() }) - it(`fires ${expectation.name} when offset is array`, () => { + it(`fires ${name} when offset is array`, () => { const callback = sandbox.spy() - const opts = { [expectation.callback]: callback } + const opts = { [callbackName]: callback } const bottomOffset = 20 const topOffset = 10 - const falseCond = [expectation.false[0][0] + topOffset, expectation.false[0][1] + bottomOffset] - const trueCond = [expectation.true[0][0] + topOffset, expectation.true[0][1] + bottomOffset] + const falsyCond = [falsy[0][0] + topOffset, falsy[0][1] + bottomOffset] + const truthyCond = [truthy[0][0] + topOffset, truthy[0][1] + bottomOffset] wrapperMount() - mockScroll(...trueCond) - mockScroll(...falseCond) + mockScroll(...truthyCond) + mockScroll(...falsyCond) callback.should.have.been.calledOnce() }) @@ -255,14 +320,14 @@ describe('Visibility', () => { describe('onPassed', () => { it('fires callback when pixels passed', () => { const onPassed = { - 20: sandbox.stub(), - '20%': sandbox.stub(), - 50: sandbox.stub(), - '50%': sandbox.stub(), - 100: sandbox.stub(), - '100%': sandbox.stub(), + 20: sandbox.spy(), + '20%': sandbox.spy(), + 50: sandbox.spy(), + '50%': sandbox.spy(), + 100: sandbox.spy(), + '100%': sandbox.spy(), } - wrapperMount() + wrapperMount() mockScroll(100, 200) onPassed[20].should.not.have.been.called('20px') @@ -293,8 +358,8 @@ describe('Visibility', () => { describe('onUpdate', () => { it('fires when scrolling', () => { const onUpdate = sandbox.spy() - wrapperMount() + mockScroll(0, 0) mockScroll(0, 0) @@ -325,39 +390,61 @@ describe('Visibility', () => { }) it('updates width and height after scroll', () => { - let calculations - const onUpdate = (e, props) => (calculations = props.calculations) + const onUpdate = sandbox.spy() wrapperMount() mockScroll(0, 100) - calculations.height.should.equal(100) - calculations.width.should.equal(window.innerWidth) + onUpdate.should.have.been.calledWithMatch(null, { + calculations: { + height: 100, + width: window.innerWidth, + }, + }) mockScroll(50, 3000) - calculations.height.should.equal(2950) - calculations.width.should.equal(window.innerWidth) + onUpdate.should.have.been.calledWithMatch(null, { + calculations: { + height: 2950, + width: window.innerWidth, + }, + }) }) it('shows passed pixels and percentage', () => { - let calculations - const onUpdate = (e, props) => (calculations = props.calculations) + const onUpdate = sandbox.spy() wrapperMount() mockScroll(0, 100) - calculations.percentagePassed.should.equal(0) - calculations.pixelsPassed.should.equal(0) + onUpdate.should.have.been.calledWithMatch(null, { + calculations: { + percentagePassed: 0, + pixelsPassed: 0, + }, + }) mockScroll(-1, 99) - calculations.percentagePassed.should.equal(0.01) - calculations.pixelsPassed.should.equal(1) + onUpdate.should.have.been.calledWithMatch(null, { + calculations: { + percentagePassed: 0.01, + pixelsPassed: 1, + }, + }) mockScroll(-2, 198) - calculations.percentagePassed.should.equal(0.01) - calculations.pixelsPassed.should.equal(2) + onUpdate.should.have.been.calledWithMatch(null, { + calculations: { + percentagePassed: 0.01, + pixelsPassed: 2, + }, + }) mockScroll(-10, 0) - calculations.percentagePassed.should.equal(1) - calculations.pixelsPassed.should.equal(10) + onUpdate.should.have.been.calledWithMatch(null, { + calculations: { + percentagePassed: 1, + pixelsPassed: 10, + }, + }) }) }) }) From 8fd6b505fd84536a3f66c9aedfa2abcdd8f541aa Mon Sep 17 00:00:00 2001 From: Alexander Fedyashov Date: Thu, 21 Sep 2017 19:01:14 +0300 Subject: [PATCH 2/3] fix(Visibility): restore `firedCallbacks` --- src/behaviors/Visibility/Visibility.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/behaviors/Visibility/Visibility.js b/src/behaviors/Visibility/Visibility.js index 5bb2c6e423..91b9147706 100644 --- a/src/behaviors/Visibility/Visibility.js +++ b/src/behaviors/Visibility/Visibility.js @@ -181,7 +181,7 @@ export default class Visibility extends Component { topVisible: false, } - occurredCallbacks = [] + firedCallbacks = [] // ---------------------------------------- // Lifecycle @@ -191,7 +191,7 @@ export default class Visibility extends Component { const cleanHappened = continuous !== this.props.continuous || once !== this.props.once // Heads up! We should clean up array of happened callbacks, if values of these props are changed - if (cleanHappened) this.occurredCallbacks = [] + if (cleanHappened) this.firedCallbacks = [] } componentDidMount() { @@ -219,10 +219,10 @@ export default class Visibility extends Component { if (!callback) return // Heads up! When `continuous` is true, callback will be fired always - if (!continuous && _.includes(this.occurredCallbacks, name)) return + if (!continuous && _.includes(this.firedCallbacks, name)) return callback(null, { ...this.props, calculations: this.calculations }) - this.occurredCallbacks.push(name) + this.firedCallbacks.push(name) } fire = ({ callback, name }, value, reverse = false) => { @@ -237,7 +237,7 @@ export default class Visibility extends Component { if (matchesDirection && executionPossible) this.execute(callback, name) // Heads up! We should remove callback from the happened when it's not `once` - if (!once) this.occurredCallbacks = _.without(this.occurredCallbacks, name) + if (!once) this.firedCallbacks = _.without(this.firedCallbacks, name) } fireOnPassed() { From b6114d63c62cdd8190df285297278a9af87d2549 Mon Sep 17 00:00:00 2001 From: Alexander Fedyashov Date: Thu, 21 Sep 2017 20:32:29 +0300 Subject: [PATCH 3/3] fix(Visibility): restore name of event handler --- src/behaviors/Visibility/Visibility.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/behaviors/Visibility/Visibility.js b/src/behaviors/Visibility/Visibility.js index 91b9147706..baf82b2ecd 100644 --- a/src/behaviors/Visibility/Visibility.js +++ b/src/behaviors/Visibility/Visibility.js @@ -199,7 +199,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.update() } @@ -207,7 +207,7 @@ export default class Visibility extends Component { if (!isBrowser) return const { context } = this.props - context.removeEventListener('scroll', this.handleUpdate) + context.removeEventListener('scroll', this.handleScroll) } // ---------------------------------------- @@ -260,7 +260,7 @@ export default class Visibility extends Component { }) } - handleUpdate = () => { + handleScroll = () => { if (this.ticking) return this.ticking = true