使用 Redux 管理视频播放器

问题描述 投票:0回答:3

使用 Redux 管理视频播放器的理想方法是什么(主要是调度播放/暂停视频的操作)?

我正在 React 应用程序中构建一个视频播放器,并且视频播放器上有事件侦听器,用于调度相关事件来更新状态。让父组件对其他组件进行操作以调度 PLAY 或 PAUSE 操作的最佳方式是什么?

例如,我想要考虑的一个用例是正在播放一个视频,而所有其他视频确保暂停播放。

我想到的两种方法是:

1) 让父组件检查

componentWillReceiveProps
中的更改,并检查类似

的内容
if (this.props.paused && !nextProps.paused) {
    this.refs.video.play()
}

2)在状态树中存储对底层视频元素的引用,并使用中间件来执行某些操作(例如

PLAY
操作),例如

if (action.type === PLAY) {
    let state = getState();
    state.players[action.payload.playerId].play();
}

一种策略会比另一种更“正确”,还是有另一种更有意义的方法?

javascript reactjs redux
3个回答
3
投票

1) 是正确的选择。

您的视频只是一个视图组件。在 React 中,你总是希望组件的 props 决定输出。

2) 的问题是视频对象不属于该状态。你告诉 Redux 太多关于实现细节的信息。 Redux 不关心实现细节;它只是一个状态容器。

更新

经过进一步思考,我建议

componentDidUpdate()
是放置此逻辑的最佳位置。即

componentDidUpdate(prevProps)
  if (prevProps.paused && !this.props.paused) {
    this.refs.video.play();
  }
}

优点是

componentDidUpdate()
在重新渲染后调用。这可能对您的目的没有影响,但在 React 有机会更新 DOM 之前触发 DOM 事件可能会导致一些不幸的竞争条件。

当然,这不会改变我建议的要点,即输出应该始终由道具(或状态)驱动。


2
投票

我认为你不需要(2),(1)就很好了。现在您只处理播放动作,但您可以在那里添加暂停,如下所示:

if (this.props.paused && !nextProps.paused) {
  this.refs.video.play()
}

if (!this.props.paused && nextProps.paused) {
  this.refs.video.pause()
}

在这种情况下,你的 html 播放器状态将与 redux 播放器状态同步。

例如,我想要考虑的一个用例是正在播放一个视频,而所有其他视频确保暂停播放。

这种情况你可以在你的reducer中处理这种情况。我会按暂停状态的 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;
  }
}

0
投票
    import { createSlice } from '@reduxjs/toolkit';

const initialState = {};

const playersSlice = createSlice({
  name: 'players',
  initialState,
  reducers: {
    pausePlayer(state, action) {
      const playerId = action.payload;
      state[playerId].paused = true;
    },
    playPlayer(state, action) {
      const playerId = action.payload;
      const previouslyPlaying = Object.entries(state).find(([id, player]) => !player.paused);

      state[playerId].paused = false;

      // Pause previously playing player only if it exists and isn't the same player
      if (previouslyPlaying && previouslyPlaying[0] !== playerId) {
        state[previouslyPlaying[0]].paused = true;
      }
    },
  },
});

export const { pausePlayer, playPlayer } = playersSlice.actions;
export default playersSlice.reducer;
© www.soinside.com 2019 - 2024. All rights reserved.