Redüktörde bir eylem gönderebilir miyim?


197

bir indirgeyicinin kendisinde bir eylem göndermek mümkün mü? Bir ilerleme çubuğu ve ses öğem var. Amaç, ses öğesinde saat güncellendiğinde ilerleme çubuğunu güncellemektir. Ancak ilerleme çubuğunu güncellemek için ontimeupdate olay işleyicisini nereye yerleştireceğinizi veya ontimeupdate geri çağrısında bir eylemin nasıl gönderileceğini bilmiyorum. İşte benim kod:

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

Nedir AudioElement? Durumun böyle bir şey olmaması gerekir.
ebuat3989

bir Ses Nesnesi tutan bir ES6 düz sınıftır (tepki yok). Durumda olmasaydı, oynat / durdur, atlamayı vb. Nasıl kontrol ederim?
klanm

2
Redux destanına bakmak isteyebilirsiniz
Kyeotic

Yanıtlar:


151

Bir indirgeyici içinde bir eylem göndermek bir anti-modeldir . Düşürücünüz yan etkisiz olmalı, sadece eylem yükünü sindirmeli ve yeni bir durum nesnesi döndürmelidir. Dinleyici eklemek ve redüktör içine eylemler göndermek zincirleme eylemlere ve diğer yan etkilere yol açabilir.

Başlangıç AudioElementsınıfınız ve olay dinleyiciniz durumdan ziyade bir bileşene aittir. Olay dinleyicisi içinde, durum güncellemesi yapılacak bir eylem gönderebilirsiniz progress.

AudioElementSınıf nesnesini yeni bir React bileşeninde başlatabilir veya bu sınıfı bir React bileşenine dönüştürebilirsiniz.

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

Doğrudan updateProgressActionotomatik dispatcholarak çağrılmanıza gerek olmadığından, öğesinin otomatik olarak sarıldığını unutmayın .


açıklama için çok teşekkür ederim! Ancak hala dağıtım programına nasıl erişeceğimi bilmiyorum. Tepki yöntemini her zaman tepki-redux'dan kullandım. ancak updateProgress yönteminde nasıl çağrılacağını bilmiyorum. Yoksa dağıtıcıyı almanın başka bir yolu var mı? belki sahne ile? teşekkür ederim
klanm

Sorun değil. Bu eylem içinde geçebilir MyAudioPlayerebeveyn kaptan bileşen connectile ed react-redux. Bunu nasıl yapacağınızı mapDispatchToPropsburadan kontrol edin: github.com/reactjs/react-redux/blob/master/docs/…
ebuat3989

6
Örneğinizde sembol nerede updateProgressActiontanımlanmıştır?
Charles Prakash Dasari

2
Bir redüktör içinde bir eylem göndermemeniz gerekiyorsa, redux-thunk redux kurallarını ihlal ediyor mu?
Eric Wiener

2
@EricWiener İndirgeyici redux-thunkdeğil, başka bir eylemden bir eylem gönderdiğine inanıyorum . stackoverflow.com/questions/35411423/…
sallf

162

Redüktörünüz bitmeden başka bir gönderim başlatmak bir anti-modeldir , çünkü redüktörünüzün başında aldığınız durum, redüktörünüz bittiğinde artık geçerli uygulama durumu olmayacaktır. Ancak bir redüktörün içinden başka bir dağıtım programlamak bir anti-kalıp DEĞİLDİR . Aslında, Elm dili budur ve bildiğiniz gibi Redux, Elm mimarisini JavaScript'e getirme girişimidir.

İşte özelliği asyncDispatchtüm eylemlerinize ekleyecek bir ara katman yazılımı . Redüktörünüz bittiğinde ve yeni uygulama durumunu iade ettiğinde, ona ne tür bir işlem yaparsanız asyncDispatchbaşlayacaktır store.dispatch.

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

Şimdi redüktörünüz bunu yapabilir:

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

7
Marcelo, buradaki blog yazınız, yaklaşımınızın koşullarını açıklayan harika bir iş çıkarıyor, bu yüzden buraya bağlıyorum
Dejay Clayton

3
Bu tam olarak ihtiyacım olan şeydi dispatch, eylemi döndürmesi gereken ara katman yazılımları olduğu gibi . Son satırları şu şekilde değiştirdim: const res = next(actionWithAsyncDispatch); syncActivityFinished = true; flushQueue(); return res;ve harika çalıştı.
Zanerock

1
Bir redüktör içinde bir eylem göndermemeniz gerekiyorsa, redux-thunk redux kurallarını ihlal ediyor mu?
Eric Wiener

Websocket yanıtlarını ele almaya çalıştığınızda bu nasıl çalışır? Bu benim redüktör dışa aktarma varsayılanım (durum, eylem) => {const m2 = [... durum.mesajlar, action.payload] Return Object.assign ({}, state, {messages: m2,})} ve I STILL Bu hatayı al "gönderiler arasında durum mutasyonu tespit edildi"
quantumpotato

12

Redux-saga gibi bir kütüphane kullanmayı deneyebilirsiniz . Eşzamansız işlevleri sıralamak, eylemleri kapatmak, gecikmeler kullanmak ve daha fazlasını yapmak için çok temiz bir yol sağlar . Çok güçlü!


1
-saga ile nasıl 'redüktör içinde başka bir sevkiyat planlayacağınızı' belirtebilir misiniz?
XPD

1
@XPD, neyi başarmak istediğinizi biraz daha açıklayabilir misiniz? Başka bir eylem göndermek için bir redüktör eylemi kullanmaya çalışıyorsanız, redux-saga'ya benzer bir şey olmadan yapamazsınız.
chandlervdw

1
Örneğin, öğelerin bir bölümünü yüklediğiniz bir öğe deponuz olduğunu varsayalım. Öğeler tembel olarak yüklenir. Bir öğenin bir tedarikçisi olduğunu varsayın. Tedarikçiler de tembel olarak yüklendi. Bu durumda, tedarikçisinin yüklenmediği bir öğe olabilir. Bir öğe indirgeyicide, henüz yüklenmemiş bir öğe hakkında bilgi almamız gerekirse, bir indirgeyici aracılığıyla sunucudan tekrar veri yüklememiz gerekir. Bu durumda redux-saga bir redüktör içinde nasıl yardımcı olur?
XPD

1
Tamam, supplierkullanıcı itemayrıntılar sayfasını ziyaret etmeye çalıştığında bu bilgi talebini başlatmak istediğinizi varsayalım . Sizin componentDidMount()bir eylem gönderir bir işlev ateşlemesi olacağını söylemek FETCH_SUPPLIER. Redüktör içinde, loading: trueistek yapılırken bir iplikçi göstermek için a gibi bir şey işaretleyebilirsiniz . redux-sagabu eylemi dinler ve buna karşılık asıl talebi reddeder. Jeneratör fonksiyonlarını kullanarak, yanıtı bekleyebilir ve içine atabilir FETCH_SUPPLIER_SUCCEEDED. İndirgeyici daha sonra mağazayı tedarikçi bilgileriyle günceller.
chandlervdw

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.