From 7c6fb5a6313fbbf8581fdf75883d74612de3ea43 Mon Sep 17 00:00:00 2001 From: NikolaBorislavovHristov Date: Wed, 25 Sep 2019 17:56:34 +0300 Subject: [PATCH] Video component reimplemented with hooks --- src/routes/Player/Video/Video.js | 106 ++++++++---------- .../Player/Video/useVideoImplementation.js | 19 ++++ 2 files changed, 67 insertions(+), 58 deletions(-) create mode 100644 src/routes/Player/Video/useVideoImplementation.js diff --git a/src/routes/Player/Video/Video.js b/src/routes/Player/Video/Video.js index 8a71c7278..bd34ece5d 100644 --- a/src/routes/Player/Video/Video.js +++ b/src/routes/Player/Video/Video.js @@ -1,77 +1,67 @@ const React = require('react'); const PropTypes = require('prop-types'); const hat = require('hat'); -const { HTMLVideo, YouTubeVideo, MPVVideo } = require('stremio-video'); +const useVideoImplementation = require('./useVideoImplementation'); -class Video extends React.Component { - constructor(props) { - super(props); - - this.containerRef = React.createRef(); - this.id = `video-${hat()}`; - this.video = null; - } - - shouldComponentUpdate() { - return false; - } - - componentWillUnmount() { - this.dispatch({ commandName: 'destroy' }); - } - - selectVideoImplementation = (args) => { - if (args.ipc) { - return MPVVideo; - } else if (args.stream.ytId) { - return YouTubeVideo; - } else { - return HTMLVideo; - } - } - - dispatch = (args = {}) => { - if (args.commandName === 'load') { - const { commandArgs = {} } = args; - const Video = this.selectVideoImplementation(commandArgs); - if (this.video === null || this.video.constructor !== Video) { - this.dispatch({ commandName: 'destroy' }); - this.video = new Video({ - id: this.id, - containerElement: this.containerRef.current, - ipc: commandArgs.ipc +const Video = React.forwardRef(({ className, ...props }, ref) => { + const [onEnded, onError, onPropValue, onPropChanged, onImplementationChanged] = React.useMemo(() => [ + props.onEnded, + props.onError, + props.onPropValue, + props.onPropChanged, + props.onImplementationChanged + ], []); + const containerElementRef = React.useRef(null); + const videoRef = React.useRef(null); + const id = React.useMemo(() => `video-${hat()}`, []); + const dispatch = React.useCallback((args) => { + if (args && args.commandName === 'load' && args.commandArgs) { + const Video = useVideoImplementation(args.commandArgs.shell, args.commandArgs.stream); + if (typeof Video !== 'function') { + videoRef.current = null; + } else if (videoRef.current === null || videoRef.current.constructor !== Video) { + dispatch({ commandName: 'destroy' }); + videoRef.current = new Video({ + id: id, + containerElement: containerElementRef.current, + shell: args.commandArgs.shell }); - this.video.on('ended', this.props.onEnded); - this.video.on('error', this.props.onError); - this.video.on('propValue', this.props.onPropValue); - this.video.on('propChanged', this.props.onPropChanged); - this.props.onImplementationChanged(this.video.constructor.manifest); + videoRef.current.on('ended', onEnded); + videoRef.current.on('error', onError); + videoRef.current.on('propValue', onPropValue); + videoRef.current.on('propChanged', onPropChanged); + onImplementationChanged(videoRef.current.constructor.manifest); } } - if (this.video !== null) { + if (videoRef.current !== null) { try { - this.video.dispatch(args); + videoRef.current.dispatch(args); } catch (e) { - console.error(this.video.constructor.manifest.name, e); + console.error(videoRef.current.constructor.manifest.name, e); } } - } + }, []); + React.useImperativeHandle(ref, () => ({ dispatch })); + React.useEffect(() => { + return () => { + dispatch({ commandName: 'destroy' }); + }; + }, []); + return ( +
+ ); +}); - render() { - return ( -
- ); - } -} +Video.displayName = 'Video'; Video.propTypes = { className: PropTypes.string, - onEnded: PropTypes.func.isRequired, - onError: PropTypes.func.isRequired, - onPropValue: PropTypes.func.isRequired, - onPropChanged: PropTypes.func.isRequired, - onImplementationChanged: PropTypes.func.isRequired + onEnded: PropTypes.func, + onError: PropTypes.func, + onPropValue: PropTypes.func, + onPropChanged: PropTypes.func, + onImplementationChanged: PropTypes.func }; module.exports = Video; diff --git a/src/routes/Player/Video/useVideoImplementation.js b/src/routes/Player/Video/useVideoImplementation.js new file mode 100644 index 000000000..89b41e33d --- /dev/null +++ b/src/routes/Player/Video/useVideoImplementation.js @@ -0,0 +1,19 @@ +const { HTMLVideo, YouTubeVideo, MPVVideo } = require('stremio-video'); + +const useVideoImplementation = (shell, stream) => { + if (shell) { + return MPVVideo; + } + + if (stream) { + if (stream.ytId) { + return YouTubeVideo; + } else { + return HTMLVideo; + } + } + + return null; +}; + +module.exports = useVideoImplementation;