1. ホーム
  2. reactjs

[解決済み】reducerでアクションをディスパッチすることはできますか?

2022-04-02 09:08:50

質問

は、reducer 自体でアクションをディスパッチすることは可能でしょうか?私はプログレスバーとオーディオ要素を持っています。目標は、audio要素で時間が更新されたときにprogressbarを更新することです。しかし、私はどこにontimeupdateイベントハンドラを配置するか、またはontimeupdateのコールバックでアクションをディスパッチし、プログレスバーを更新する方法が分かりません。以下は私のコードです。

//reducer

const initialState = {
    audioElement: new AudioElement('test.mp3'),
    progress: 0.0
}

initialState.audioElement.audio.ontimeupdate = () => {
    console.log('progress', initialState.audioElement.currentTime/initialState.audioElement.duration);
    //how to dispatch 'SET_PROGRESS_VALUE' now?
};


const audio = (state=initialState, action) => {
    switch(action.type){
        case 'SET_PROGRESS_VALUE':
            return Object.assign({}, state, {progress: action.progress});
        default: return state;
    }

}

export default audio;

解決方法は?

reducer内でアクションをディスパッチすることはアンチパターンである . リデューサーは副作用がなく、単にアクションのペイロードを消化して新しいステートオブジェクトを返すだけであるべきです。リスナーを追加して、アクションをリデューサ内でディスパッチすると、アクションの連鎖やその他の副作用を引き起こす可能性があります。

を初期化したようです。 AudioElement クラスとイベントリスナーは、ステートではなくコンポーネントに属しています。イベントリスナー内でアクションをディスパッチすることができ、それによって progress を状態表示します。

を初期化することもできます。 AudioElement クラスオブジェクトを新しい React コンポーネントで使用するか、そのクラスを React コンポーネントに変換するだけです。

class MyAudioPlayer extends React.Component {
  constructor(props) {
    super(props);

    this.player = new AudioElement('test.mp3');

    this.player.audio.ontimeupdate = this.updateProgress;
  }

  updateProgress () {
    // Dispatch action to reducer with updated progress.
    // You might want to actually send the current time and do the
    // calculation from within the reducer.
    this.props.updateProgressAction();
  }

  render () {
    // Render the audio player controls, progress bar, whatever else
    return <p>Progress: {this.props.progress}</p>;
  }
}

class MyContainer extends React.Component {
   render() {
     return <MyAudioPlayer updateProgress={this.props.updateProgress} />
   }
}

function mapStateToProps (state) { return {}; }

return connect(mapStateToProps, {
  updateProgressAction
})(MyContainer);

ただし updateProgressAction で自動的にラップされます。 dispatch ということで、ディスパッチを直接呼び出す必要はありません。