使用 Redux 管理视频播放器
Using Redux to Manage a Video Player
使用 Redux 管理视频播放器的理想方式是什么,主要是针对 play/pause 视频的调度操作?
我正在 React 应用程序中构建视频播放器,我在视频播放器上有事件侦听器,可以调度相关事件来更新状态。让父组件对其他组件执行 PLAY 或 PAUSE 操作的最佳方式是什么?
例如,我要说明的一个用例是一个视频正在播放,而所有其他视频确保暂停播放。
我想到的两种方式是:
1) 让父组件检查 componentWillReceiveProps
中的更改,并检查类似
的内容
if (this.props.paused && !nextProps.paused) {
this.refs.video.play()
}
2)在状态树中存储对底层video元素的引用,并使用中间件来作用于某些动作(例如PLAY
动作),例如
if (action.type === PLAY) {
let state = getState();
state.players[action.payload.playerId].play();
}
一种策略会比另一种更 "correct" 吗,还是有另一种方法更有意义?
1) 是必经之路。
您的视频只是一个视图组件。在 React 中,您总是希望组件的 props 决定输出。
2) 的问题是视频对象不属于状态。你对 Redux 的实现细节说得太多了。 Redux 不关心实现细节;它只是一个状态容器。
更新
进一步思考,我建议 componentDidUpdate()
是放置此逻辑的最佳位置。即
componentDidUpdate(prevProps)
if (prevProps.paused && !this.props.paused) {
this.refs.video.play();
}
}
优点是componentDidUpdate()
在重新渲染后被调用。它可能对您的目的没有影响,但有可能在 React 有机会更新 DOM 之前触发 DOM 事件可能会导致一些不幸的竞争条件。
当然,这不会改变我的建议的要点,即输出应该始终由道具(或状态)驱动。
我认为你不需要(2),(1)很好。现在你只处理播放动作,但你可以在那里添加暂停,如下所示:
if (this.props.paused && !nextProps.paused) {
this.refs.video.play()
}
if (!this.props.paused && nextProps.paused) {
this.refs.video.pause()
}
在这种情况下,您的 html 播放器状态将与 redux 播放器状态同步。
One use case that I would want to account for, for example, is one video being played and all other videos making sure to pause their playback.
在这种情况下,您可以在减速器中处理这种情况。我会通过暂停状态的 ID 存储所有玩家,例如:
{
1: {
paused: true,
},
2: {
paused: false,
},
...
}
您需要在您的操作中添加玩家 ID 并暂停其他玩家,当您收到 PLAY
操作时:
function players(state = {}, action) {
switch (action.type) {
case PAUSE:
return {
...state,
[action.id]: {
paused: true
}
}
case PLAY:
const nowPlaying = Object.keys(state).find(id => !state[id].paused);
const newState = {
...state,
[action.id]: {
paused: false
}
};
if (nowPlaying) {
newState[nowPlaying].paused = true;
}
return newState;
}
}
使用 Redux 管理视频播放器的理想方式是什么,主要是针对 play/pause 视频的调度操作?
我正在 React 应用程序中构建视频播放器,我在视频播放器上有事件侦听器,可以调度相关事件来更新状态。让父组件对其他组件执行 PLAY 或 PAUSE 操作的最佳方式是什么?
例如,我要说明的一个用例是一个视频正在播放,而所有其他视频确保暂停播放。
我想到的两种方式是:
1) 让父组件检查 componentWillReceiveProps
中的更改,并检查类似
if (this.props.paused && !nextProps.paused) {
this.refs.video.play()
}
2)在状态树中存储对底层video元素的引用,并使用中间件来作用于某些动作(例如PLAY
动作),例如
if (action.type === PLAY) {
let state = getState();
state.players[action.payload.playerId].play();
}
一种策略会比另一种更 "correct" 吗,还是有另一种方法更有意义?
1) 是必经之路。
您的视频只是一个视图组件。在 React 中,您总是希望组件的 props 决定输出。
2) 的问题是视频对象不属于状态。你对 Redux 的实现细节说得太多了。 Redux 不关心实现细节;它只是一个状态容器。
更新
进一步思考,我建议 componentDidUpdate()
是放置此逻辑的最佳位置。即
componentDidUpdate(prevProps)
if (prevProps.paused && !this.props.paused) {
this.refs.video.play();
}
}
优点是componentDidUpdate()
在重新渲染后被调用。它可能对您的目的没有影响,但有可能在 React 有机会更新 DOM 之前触发 DOM 事件可能会导致一些不幸的竞争条件。
当然,这不会改变我的建议的要点,即输出应该始终由道具(或状态)驱动。
我认为你不需要(2),(1)很好。现在你只处理播放动作,但你可以在那里添加暂停,如下所示:
if (this.props.paused && !nextProps.paused) {
this.refs.video.play()
}
if (!this.props.paused && nextProps.paused) {
this.refs.video.pause()
}
在这种情况下,您的 html 播放器状态将与 redux 播放器状态同步。
One use case that I would want to account for, for example, is one video being played and all other videos making sure to pause their playback.
在这种情况下,您可以在减速器中处理这种情况。我会通过暂停状态的 ID 存储所有玩家,例如:
{
1: {
paused: true,
},
2: {
paused: false,
},
...
}
您需要在您的操作中添加玩家 ID 并暂停其他玩家,当您收到 PLAY
操作时:
function players(state = {}, action) {
switch (action.type) {
case PAUSE:
return {
...state,
[action.id]: {
paused: true
}
}
case PLAY:
const nowPlaying = Object.keys(state).find(id => !state[id].paused);
const newState = {
...state,
[action.id]: {
paused: false
}
};
if (nowPlaying) {
newState[nowPlaying].paused = true;
}
return newState;
}
}