admin管理员组

文章数量:1404567

What would be the ideal way to manage a video player using Redux, primarily in terms of dispatching actions to play/pause a video?

I'm working on building a video player in a React application, and I have event listeners on the video player dispatching relevant events to update the state. What would be the best way to have the parent ponent act on other ponents dispatching a PLAY or PAUSE action?

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.

Two ways that I've thought of would be:

1) Have the parent ponent check for changes in ponentWillReceiveProps, and checking for something like

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

2) Store a reference to the underlying video element in the state tree, and using middleware to act on certain actions (such as a PLAY action), such as

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

Would one strategy be more "correct" than the other, or is there another way that would make more sense?

What would be the ideal way to manage a video player using Redux, primarily in terms of dispatching actions to play/pause a video?

I'm working on building a video player in a React application, and I have event listeners on the video player dispatching relevant events to update the state. What would be the best way to have the parent ponent act on other ponents dispatching a PLAY or PAUSE action?

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.

Two ways that I've thought of would be:

1) Have the parent ponent check for changes in ponentWillReceiveProps, and checking for something like

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

2) Store a reference to the underlying video element in the state tree, and using middleware to act on certain actions (such as a PLAY action), such as

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

Would one strategy be more "correct" than the other, or is there another way that would make more sense?

Share Improve this question asked Mar 9, 2016 at 18:06 Andrew BurgessAndrew Burgess 5,2965 gold badges33 silver badges37 bronze badges 1
  • Did you ever find a solution that was satisfactory for your needs? Have any examples of this implemented? – Joshua F. Rountree Commented Jun 4, 2018 at 12:01
Add a ment  | 

3 Answers 3

Reset to default 3

1) is the way to go.

Your video is simply a view ponent. In React you always want the ponent's props to dictate the output.

The problem with 2) is that the video object doesn't belong in the state. You're telling Redux too much about the implementation detail. Redux doesn't care about the implementation detail; it's just a state container.

UPDATE

On further reflection, I remend ponentDidUpdate() is the best place to place this logic. i.e.

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

The advantage being that ponentDidUpdate() is called after re-rendering. It may not make a difference for your purposes, but it's possible that triggering a DOM event before React has had a chance to update the DOM may cause some unfortunate race conditions.

Of course this doesn't change the gist of my advice that output should always be props (or state) driven.

I don't think that you need (2), (1) is pretty good. Now you handle only play action, but you can add pause there, like this:

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

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

In this case your html player state will be synchronized with redux player state.

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.

In this case you can handle this situation in your reducer. I'd store all players by ids with paused state, like:

{
 1: {
   paused: true, 
 },
 2: {
   paused: false,
 },
 ...
}

You need to add player id in your action and pause other players, when you receive PLAY action:

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;
  }
}
    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;

本文标签: javascriptUsing Redux to Manage a Video PlayerStack Overflow