Bisakah saya mengirim tindakan dalam peredam?

196

apakah mungkin mengirim tindakan dalam peredam itu sendiri? Saya memiliki progressbar dan elemen audio. Tujuannya adalah untuk memperbarui progressbar ketika waktu diperbarui dalam elemen audio. Tapi saya tidak tahu di mana harus menempatkan eventhandler ontimeupdate, atau bagaimana mengirim tindakan dalam panggilan balik ontimeupdate, untuk memperbarui progressbar. Ini kode saya:

//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;
klanm
sumber
Apa AudioElement? Sepertinya itu seharusnya tidak menjadi sesuatu dalam keadaan.
ebuat3989
ini adalah kelas polos ES6 (tidak bereaksi), memegang Objek Audio. Jika tidak ada di negara bagian, bagaimana saya mengontrol permainan / berhenti, melewatkan dll?
klanm
2
Anda mungkin ingin melihat
redux

Jawaban:

150

Mengirim tindakan dalam peredam adalah anti-pola . Peredam Anda harus tanpa efek samping, cukup mencerna payload tindakan dan mengembalikan objek keadaan baru. Menambahkan pendengar dan mengirim tindakan dalam peredam dapat menyebabkan aksi berantai dan efek samping lainnya.

Kedengarannya seperti AudioElementkelas yang diinisialisasi Anda dan pendengar acara termasuk dalam komponen dan bukan dalam keadaan. Dalam pendengar acara, Anda dapat mengirim tindakan, yang akan diperbaruiprogress dalam keadaan.

Anda dapat menginisialisasi AudioElementobjek kelas di komponen Bereaksi baru atau hanya mengkonversi kelas itu ke komponen Bereaksi.

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

Perhatikan bahwa updateProgressActionsecara otomatis dibungkus dengan dispatchsehingga Anda tidak perlu menelepon pengiriman langsung.

ebuat3989
sumber
terima kasih banyak atas klarifikasi! Tapi saya masih tidak tahu cara mengakses dispatcher. Saya selalu menggunakan metode connect dari react-redux. tapi saya tidak tahu bagaimana menyebutnya dengan metode updateProgress. Atau ada cara lain untuk mendapatkan operator. mungkin dengan alat peraga? terima kasih
klanm
Tidak masalah. Anda bisa meneruskan aksi ke MyAudioPlayerkomponen dari wadah induk yang connectdiedit bersama react-redux. Lihat cara melakukannya dengan di mapDispatchToPropssini: github.com/reactjs/react-redux/blob/master/docs/…
ebuat3989
6
Di mana simbol updateProgressActiondidefinisikan dalam contoh Anda?
Charles Prakash Dasari
2
Jika Anda tidak seharusnya mengirim tindakan dalam peredam, maka apakah redux-thunk melanggar aturan redux?
Eric Wiener
2
@ EricWiener, saya percaya redux-thunkmengirimkan tindakan dari tindakan lain, bukan peredam. stackoverflow.com/questions/35411423/…
sallf
160

Memulai pengiriman lain sebelum peredam Anda selesai adalah anti-pola , karena status yang Anda terima di awal peredam Anda tidak akan menjadi status aplikasi saat ini saat peredam Anda selesai. Tapi menjadwalkan pengiriman lain dari dalam peredam BUKAN anti-pola . Sebenarnya, itulah yang dilakukan bahasa Elm, dan seperti yang Anda ketahui Redux adalah upaya untuk membawa arsitektur Elm ke JavaScript.

Ini adalah middleware yang akan menambahkan properti asyncDispatchke semua tindakan Anda. Ketika peredam Anda telah selesai dan mengembalikan status aplikasi baru, asyncDispatchakan terpicu store.dispatchdengan tindakan apa pun yang Anda berikan.

// This middleware will just add the property "async dispatch"
// to actions with the "async" propperty set to true
const asyncDispatchMiddleware = store => next => action => {
  let syncActivityFinished = false;
  let actionQueue = [];

  function flushQueue() {
    actionQueue.forEach(a => store.dispatch(a)); // flush queue
    actionQueue = [];
  }

  function asyncDispatch(asyncAction) {
    actionQueue = actionQueue.concat([asyncAction]);

    if (syncActivityFinished) {
      flushQueue();
    }
  }

  const actionWithAsyncDispatch =
    Object.assign({}, action, { asyncDispatch });

  const res = next(actionWithAsyncDispatch);

  syncActivityFinished = true;
  flushQueue();

  return res;
};

Sekarang peredam Anda dapat melakukan ini:

function reducer(state, action) {
  switch (action.type) {
    case "fetch-start":
      fetch('wwww.example.com')
        .then(r => r.json())
        .then(r => action.asyncDispatch({ type: "fetch-response", value: r }))
      return state;

    case "fetch-response":
      return Object.assign({}, state, { whatever: action.value });;
  }
}
Marcelo Lazaroni
sumber
7
Marcelo, posting blog Anda di sini sangat membantu menggambarkan keadaan pendekatan Anda, jadi saya menautkannya di sini: lazamar.github.io/dispatching-from-inside-of-reducers
Dejay Clayton
3
Ini persis apa yang saya butuhkan, kecuali istirahat middleware apa adanya dispatchyang harus mengembalikan tindakan. Saya mengubah baris terakhir menjadi: const res = next(actionWithAsyncDispatch); syncActivityFinished = true; flushQueue(); return res;dan itu bekerja dengan baik.
zanerock
1
Jika Anda tidak seharusnya mengirim tindakan dalam peredam, maka apakah redux-thunk melanggar aturan redux?
Eric Wiener
Bagaimana cara kerjanya saat Anda mencoba menangani respons websocket? Ini adalah standar ekspor peredam saya (state, action) => {const m2 = [... state.messages, action.payload] return Object.assign ({}, state, {messages: m2,})} dan SAYA MASIH dapatkan kesalahan ini "keadaan mutasi terdeteksi di antara pengiriman"
quantumpotato
12

Anda dapat mencoba menggunakan perpustakaan seperti redux-saga . Ini memungkinkan untuk cara yang sangat bersih untuk mengurutkan fungsi-fungsi async, menjalankan aksi, menggunakan penundaan dan banyak lagi. Ini sangat kuat!

chandlervdw
sumber
1
dapatkah Anda menentukan cara mencapai 'penjadwalan pengiriman yang lain di dalam peredam' dengan redux-saga?
XPD
1
@XPD dapatkah Anda menjelaskan sedikit lebih banyak tentang apa yang ingin Anda capai? Jika Anda mencoba menggunakan tindakan peredam untuk mengirim tindakan lain, Anda tidak akan bisa tanpa sesuatu yang mirip dengan redux-saga.
chandlervdw
1
Sebagai contoh, misalkan Anda memiliki toko item di mana Anda telah memuat bagian dari item tersebut. Item dimuat dengan malas. Anggap suatu barang memiliki pemasok. Pemasok juga dimuat dengan malas. Jadi dalam hal ini mungkin ada item yang pemasoknya belum dimuat. Dalam item reducer, jika kita perlu mendapatkan informasi tentang item yang belum dimuat, kita harus memuat data dari server lagi melalui reducer. Dalam hal itu bagaimana redux-saga membantu di dalam peredam?
XPD
1
Oke, misalkan Anda ingin memadamkan permintaan supplierinfo ini ketika pengguna mencoba mengunjungi itemhalaman detail. Anda componentDidMount()akan menjalankan fungsi yang mengirimkan tindakan, katakanlah FETCH_SUPPLIER. Di dalam peredam, Anda dapat mencentang pada sesuatu seperti loading: trueuntuk menunjukkan pemintal saat permintaan dibuat. redux-sagaakan mendengarkan tindakan itu, dan sebagai tanggapan, mematikan permintaan yang sebenarnya. Memanfaatkan fungsi generator, ia dapat menunggu respons dan membuangnya FETCH_SUPPLIER_SUCCEEDED. Peredam kemudian memperbarui toko dengan info pemasok.
chandlervdw
6

redux-loop mengambil isyarat dari Elm dan memberikan pola ini.

Quang Van
sumber