2016-05-10 25 views
10

Stavo lavorando a un progetto React & Redux. Il progetto usava utilizzare webpack-dev-middleware e hot middleware per ricaricare a caldo.Redux Saga hot reloading

Dopo aver aggiunto Redux Saga al progetto e aggiunto il middleware di saga all'archivio di ripristino. Sembra che ogni volta che cambia i codici saga, il ricarico volontà caldo si è rotto e visualizza un messaggio di errore:

Provider> non supporta la modifica store al volo. È molto probabile che tu veda questo errore perché hai aggiornato a Redux 2.xe React Redux 2.x che non sono più automaticamente riduttori di ricarica caldi. Vedere https://github.com/reactjs/react-redux/releases/tag/v2.0.0 per le istruzioni di migrazione.

Capisco che Saga utilizza i generatori e dipende dal tempo. È possibile ricaricare la pagina con Sagas? proprio come i riduttori Redux si sostituiscono durante il ricaricamento a caldo.

Grazie!

+0

Vedere la discussione https://github.com/yelouafi/redux-saga/issues/22#issuecomment-218522365 –

risposta

16

Sto lavorando a un progetto con redux e redux-saga (ma non reagire). Ho implementato il ricaricamento a caldo delle saghe usando sagaMiddleware.run() ma devi gestire il modulo ricaricando e sostituendo riduttori e sagas come indicato nel link che hai fornito (https://github.com/reactjs/react-redux/releases/tag/v2.0.0).

import { createStore } from 'redux'; 
import rootReducer from '../reducers/index'; 
import getSagas from '../sagas'; 

export default function configureStore(initialState) { 
    const sagaMiddleware = createSagaMiddleware() 
    const store = createStore(rootReducer, initialState, applyMiddleware(sagaMiddleware)); 
    let sagaTask = sagaMiddleware.run(function*() { 
    yield getSagas() 
    }) 
    if (module.hot) { 
    // Enable Webpack hot module replacement for reducers 
    module.hot.accept('../reducers',() => { 
     const nextRootReducer = require('../reducers/index'); 
     store.replaceReducer(nextRootReducer); 
    }); 
    module.hot.accept('../sagas',() => { 
     const getNewSagas = require('../sagas'); 
     sagaTask.cancel() 
     sagaTask.done.then(() => { 
     sagaTask = sagaMiddleware.run(function* replacedSaga (action) { 
      yield getNewSagas() 
     }) 
     }) 
    }) 
    } 

    return store; 
} 

Una cosa importante da notare è la funzione getSagas(). Restituisce un array di oggetti generatore di saghe appena creati, non è possibile avere un oggetto precreatato nell'array da alcune saghe già in esecuzione. Se si acquista questo array solo in un modulo, è possibile utilizzare direttamente un array costante, ma se lo si crea componendo saghe da moduli diversi è necessario essere sicuri di ricreare saghe da tutti i moduli, quindi il modo migliore è che tutto i moduli esportano creando la funzione invece di esportare una saga fissa o una serie di saghe. Per esempio potrebbe essere una funzione come questa:

export default() => [ 
    takeEvery(SOME_ACTION, someActionSaga), 
    takeEvery(OTHER_ACTION, otherActionSaga), 
] 

Ovviamente tutte le saghe vengono riavviati dall'inizio e se si dispone di un complesso saghe con stato interno si perde lo stato attuale.

Un approccio molto simile è quello di utilizzare una saga dinamica al posto di chiamare sagaMidleware.run(), una soluzione molto simile ma è possibile ricaricare sottoinsiemi delle saghe e gestirli in modi diversi. Per maggiori informazioni vedi https://gist.github.com/mpolci/f44635dc761955730f8479b271151cf2

+1

Risolto il problema. @kevin, puoi contrassegnarlo come la risposta giusta se ha risolto il tuo problema. – wrick17

+0

@mpolci puoi spiegare di più sulla funzione getSagas? Capisco che tu voglia ottenere una serie di oggetti generatore di saga, ma se hai più file Saga che esportano listener, consiglieresti di importarli e chiamarli come una catena? 'importa getSaga1 da '../ saga1'' importa getSaga2 da' ../ saga2' e poi in sagaTask' getSaga1() getSaga2() ' – mattgabor