Skip to content

Commit 433f08c

Browse files
authored
#79 Unbind events on unmounting (#83)
1 parent 76c03e2 commit 433f08c

File tree

3 files changed

+81
-28
lines changed

3 files changed

+81
-28
lines changed

src/video/constants.js

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
export const EVENTS = [
2-
'onAbort',
3-
'onCanPlay',
4-
'onCanPlayThrough',
5-
'onDurationChange',
6-
'onEmptied',
7-
'onEncrypted',
8-
'onEnded',
9-
'onError',
10-
'onLoadedData',
11-
'onLoadedMetadata',
12-
'onLoadStart',
13-
'onPause',
14-
'onPlay',
15-
'onPlaying',
16-
'onProgress',
17-
'onRateChange',
18-
'onSeeked',
19-
'onSeeking',
20-
'onStalled',
21-
'onSuspend',
22-
'onTimeUpdate',
23-
'onVolumeChange',
24-
'onWaiting'
2+
'abort',
3+
'canPlay',
4+
'canPlayThrough',
5+
'durationChange',
6+
'emptied',
7+
'encrypted',
8+
'ended',
9+
'error',
10+
'loadedData',
11+
'loadedMetadata',
12+
'loadStart',
13+
'pause',
14+
'play',
15+
'playing',
16+
'progress',
17+
'rateChange',
18+
'seeked',
19+
'seeking',
20+
'stalled',
21+
'suspend',
22+
'timeUpdate',
23+
'volumeChange',
24+
'waiting'
2525
];
2626

2727
export const TRACKEVENTS = [
28-
'onChange',
29-
'onAddTrack',
30-
'onRemoveTrack'
28+
'change',
29+
'addTrack',
30+
'removeTrack'
3131
];
3232

3333
export const METHODS = [

src/video/video.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,14 @@ export default (
5454

5555
bindEventsToUpdateState() {
5656
EVENTS.forEach(event => {
57-
this.videoEl[event.toLowerCase()] = this.updateState;
57+
this.videoEl.addEventListener(event.toLowerCase(), this.updateState);
5858
});
5959

6060
TRACKEVENTS.forEach(event => {
61-
this.videoEl.textTracks[event.toLowerCase()] = this.updateState;
61+
// TODO: JSDom does not have this method on
62+
// `textTracks`. Investigate so we can test this without this check.
63+
this.videoEl.textTracks.addEventListener
64+
&& this.videoEl.textTracks.addEventListener(event.toLowerCase(), this.updateState);
6265
});
6366

6467
// If <source> elements are used instead of a src attribute then
@@ -73,6 +76,29 @@ export default (
7376
}
7477
}
7578

79+
unbindEvents() {
80+
EVENTS.forEach(event => {
81+
this.videoEl.removeEventListener(event.toLowerCase(), this.updateState);
82+
});
83+
84+
TRACKEVENTS.forEach(event => {
85+
// TODO: JSDom does not have this method on
86+
// `textTracks`. Investigate so we can test this without this check.
87+
this.videoEl.textTracks.removeEventListener
88+
&& this.videoEl.textTracks.removeEventListener(event.toLowerCase(), this.updateState);
89+
});
90+
91+
const sources = this.videoEl.getElementsByTagName('source');
92+
if (sources.length) {
93+
const lastSource = sources[sources.length - 1];
94+
lastSource.removeEventListener('error', this.updateState);
95+
}
96+
}
97+
98+
componentWillUnmount() {
99+
this.unbindEvents();
100+
}
101+
76102
// Stop `this.el` from being null briefly on every render,
77103
// see: https://github.com/mderrick/react-html5video/pull/65
78104
setRef(el) {

src/video/video.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import { mount, shallow } from 'enzyme';
33
import video from './video';
4+
import { EVENTS } from './constants';
45

56
const TestControl = ({ duration }) => {
67
return (
@@ -85,6 +86,32 @@ describe('video', () => {
8586
});
8687
});
8788
});
89+
90+
it('should remove all event listeners from the video element when unmounted', () => {
91+
const removeEventListenerSpy = jest.fn();
92+
component = mount(
93+
<Component autoPlay />
94+
);
95+
const updateState = component.instance().updateState;
96+
component.find('video').node.removeEventListener = removeEventListenerSpy;
97+
expect(removeEventListenerSpy).not.toHaveBeenCalled();
98+
component.unmount();
99+
EVENTS.forEach((event) => {
100+
expect(removeEventListenerSpy).toHaveBeenCalledWith(event.toLowerCase(), updateState);
101+
});
102+
});
103+
104+
it('should remove "error" event listener from the source element when unmounted', () => {
105+
const removeEventListenerSpy = jest.fn();
106+
component = mount(
107+
<Component autoPlay />
108+
);
109+
const updateState = component.instance().updateState;
110+
component.find('source').node.removeEventListener = removeEventListenerSpy;
111+
expect(removeEventListenerSpy).not.toHaveBeenCalled();
112+
component.unmount();
113+
expect(removeEventListenerSpy).toHaveBeenCalledWith('error', updateState);
114+
});
88115
});
89116

90117
describe('mapping to props', () => {

0 commit comments

Comments
 (0)