2016-04-19 15 views
68

Bir redüktörün kendisinde bir eylem göndermek mümkün mü? Bir ilerleme çubuğum ve bir ses elemanım var. Amaç, ses öğesinde zaman güncellendiğinde ilerleme çubuğunu güncellemektir. Ama ontimeupdate olay yerine yerleştiricisini nereye koyacağımı veya ilerleme çubuğunu güncellemek için, herhangi bir eylemin nasıl çalıştığını bilmiyorum. İşte benim kodudur:Redüktörde bir eylem gönderebilir miyim?

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

? Durumda bir şey olmamalı gibi görünüyor. – mtaube

+0

, bir Ses Nesnesini tutan bir ES6 düz sınıfıdır (tepki yok). Durumda olmazsa, nasıl oynayacağımı/durduğumu, atlamayı vb. Nasıl kontrol ederim? – vacetahanna

+1

Redux destanına bakmak isteyebilirsiniz – Tyrsius

cevap

57

bir redüktör içinde bir eylem Sevk bir anti-desen olduğunu. Redüktörünüz yan etki olmadan, sadece işlem yükünü sindirerek ve yeni bir durum nesnesini döndürerek olmalıdır. Dinleyicileri eklemek ve redüktör içinde eylemleri göndermek zincirleme eylemlere ve diğer yan etkilere yol açabilir.

Başlatılan AudioElement sınıfına benzer ve olay dinleyicisi, durumdan ziyade bir bileşenin içinde yer alır. Olay dinleyicisi içinde, progress durumunu güncelleyecek bir eylem gönderebilirsiniz.

AudioElement sınıf nesnesini yeni bir Yanıtla bileşeninde başlatabilir veya yalnızca bu sınıfı bir Yanıtlama bileşenine dönüştürebilirsiniz. updateProgressAction otomatik dispatch ile sarılmış olduğu

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.updateProgress(); 
    } 

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

Not böylece doğrudan sevk aramaya gerek yoktur.

+0

Açıklama için çok teşekkür ederim! Ama yine de dağıtıcıya nasıl erişeceğimi bilmiyorum. Her zaman bağlantı yöntemini tepki-redux'dan kullandım. ama updateProgress yönteminde nasıl arayacağımı bilmiyorum. Veya memuru almanın başka bir yolu var. belki sahne ile? teşekkürler – vacetahanna

+0

Sorun değil. Eylemi '' MyAudioPlayer'' bileşenine '' rea-redux'' ile '' '' '' '' bağlanan ana kapsayıcıdan geçirebilirsiniz. Bunu, '' mapDispatchToProps'' ile nasıl yapacağınıza bakın: https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options – mtaube

+0

Daha fazla bilgi için düzenleme konusuna bakın ipuçları. – mtaube

9

redux-saga gibi bir kitaplık kullanmayı deneyebilirsiniz. Zaman uyumsuzluk fonksiyonlarını sıralamak, eylemleri kapatmak, gecikmeleri kullanmak ve daha fazlası için çok temiz yol sağlar. Bu çok güçlü! Eğer redüktör başında alınan devlet artık zaman redüktör bitirir geçerli uygulama durumu olmayacak çünkü redüktör bitmeden başka sevkini başlayarak

+0

redux-saga ile 'redüktörün içindeki başka bir gönderimi zamanlama' nasıl gerçekleştirileceğini belirtebilir misiniz? – XPD

+1

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

+0

Örneğin, öğelerin bir kısmını yüklediğiniz bir öğe deponuz olduğunu varsayalım. Öğeler tembel olarak yüklenir. Bir öğenin bir tedarikçiye sahip olduğunu varsayalım. Tedarikçiler de tembel yüklü. Bu durumda, tedarikçisinin yüklenmemiş olduğu bir öğe olabilir. Bir öğe redüktöründe, henüz yüklenmemiş bir öğe hakkında bilgi almamız gerekirse, bir redüktör üzerinden veriyi tekrar sunucudan yüklememiz gerekir. Bu durumda redux-saga redüktörün içinde nasıl yardımcı olur? – XPD

42

, bir anti-desen olduğunu. Ancak redüktör içerisinden başka bir gönderim planlaması, bir anti-desen DEĞİLDİR. Aslında, Elm dilinin yaptığı şeydir ve bildiğiniz üzere, Redux, Elm mimarisini JavaScript'e getirme girişimidir.

Tüm işlemleriniz için asyncDispatch özelliğini ekleyeceğiniz bir katmanı burada bulabilirsiniz. Redüktörünüz yeni uygulama durumunu bitirdiğinde ve geri döndürdüğünde, asyncDispatchstore.dispatch'u ne şekilde harekete geçirirse onu tetikleyecektir.

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

    next(actionWithAsyncDispatch); 
    syncActivityFinished = true; 
    flushQueue(); 
}; 

Şimdi redüktör bunu yapabilirsiniz:

`` AudioElement`` nedir
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 });; 
    } 
} 
+2

Marcelo, blog yayınınız, yaklaşımınızın koşullarını açıklayan harika bir iş çıkardı, ben de burada bağlantı kurarım: https://lazamar.github.io/dispatching-from-inside-of-reducers/ –

İlgili konular