Skip to content

Instantly share code, notes, and snippets.

@mpolci
Last active January 14, 2022 22:05
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mpolci/f44635dc761955730f8479b271151cf2 to your computer and use it in GitHub Desktop.
Save mpolci/f44635dc761955730f8479b271151cf2 to your computer and use it in GitHub Desktop.
Helper function creating a dynamic saga for code splitting with redux-saga

Helper function

This function create a saga that runs the sagas in the startingSagas array and takes the actions with type indicated by changeActionType to replace the running sagas. The replacing actions must have a field sagas cointaining the array with the new sagas.

function createDynamicSaga (changeActionType, startingSagas) {
  function* _start (sagas) {
    try {
      yield sagas
    } catch (e) {
      console.error('error', e)
    }
  }
  return function* dynamicSaga () {
    let action
    let rootTask = yield fork(_start, startingSagas)
    while (action = yield take(changeActionType)) {
      yield cancel(rootTask)
      rootTask = yield fork(_start, action.sagas)
    }
  }
}

Example

How to use:

const rootSagas = [
   // ... my sagas
]
const sagaMiddleware = createSagaMiddleware()
const store = createStore(myReducers, INITIAL_STATE, applyMiddleware(sagaMiddleware))
sagaMiddleware.run(createDynamicSaga('SET_SAGAS', rootSagas))

// ...

// replace sagas
store.dispatch({ type: 'SET_SAGAS', sagas: [ /* ... new sagas */ ] })

The example shows how to create a root dynamic saga but this is function can also be used to create dynamic sub sagas to have some fixed sagas and some replaceable sagas.

Troubleshooting

Your sagas are called with an undefined action immediatelly after the sagas are replaced

When replacing sagas, do not reuse generator objects from previous running sagas. If you want to reuse old sagas you have to recreate them.

Wrong:

const reusedSaga = [
  takeEvery(SOME_ACTION, someActionSaga)
]

// ...

store.dispatch({ type: 'SET_SAGAS', sagas: [ 
  ...reusedSaga,
  // some other new sagas
]})

Change to:

const getReusedSaga = () => [
  takeEvery(SOME_ACTION, someActionSaga)
]

// ...

store.dispatch({ type: 'SET_SAGAS', sagas: [ 
  ...getReusedSaga(),
  // some other new sagas
]})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment