Multiple redux-sagas
Solution 1
Of course, that is the whole point of sagas.
A typical application will have multiple sagas waiting in the background, waiting for a particular action / actions (take
effect).
Below is an example of how you can setup multiple sagas from redux-saga issue#276:
./saga.js
function* rootSaga () {
yield [
fork(saga1), // saga1 can also yield [ fork(actionOne), fork(actionTwo) ]
fork(saga2),
];
}
./main.js
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import rootReducer from './reducers'
import rootSaga from './sagas'
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
rootReducer,
applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(rootSaga)
Solution 2
Redux Saga uses the all
function in the recent version (0.15.3) to combine multiple sagas to one root saga for the Redux store.
import { takeEvery, all } from 'redux-saga/effects';
...
function *watchAll() {
yield all([
takeEvery("FRIEND_FETCH_REQUESTED", fetchFriends),
takeEvery("CREATE_USER_REQUESTED", createUser)
]);
}
export default watchAll;
In the Redux store you can use the root saga for the saga middleware:
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import rootReducer from './reducers';
import rootSaga from './sagas';
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
rootReducer,
applyMiddleware(sagaMiddleware)
);
sagaMiddleware.run(rootSaga)
Solution 3
This has changed a bit since last answers were posted. The preferred way to create root saga, as documented at https://redux-saga.js.org/docs/advanced/RootSaga.html, is using spawn
:
export default function* rootSaga() {
yield spawn(saga1)
yield spawn(saga2)
yield spawn(saga3)
}
spawn
is an effect that will disconnect your child saga from its parent, allowing it to fail without crashing its parent. This simply means that even if one saga were to fail, the rootSaga
and other sagas will not be killed.
There is also way of recovering sagas that fail (more info on that is available in the link mentioned above).
Related videos on Youtube
IntoTheDeep
Like most of us, I was born. Some years later I created my first website. I love traveling and I'm an espresso snob. I share my knowledge about the web with my students in college and I would love to teach at your company. For those that are interested in old school paper, I have a bachelor degree in IT and a master degree in commercial sciences. Yup, that last one is for making sure I earn more than I spend. I love running, I even made an app for making running with others easier. If you ever feel like going for a run and talk shop, I’m cool with that.
Updated on July 09, 2022Comments
-
IntoTheDeep almost 2 years
I use react-redux and redux-saga for API calls from this example. My target is to do another API calls with different urls and to use them in different pages. How to achieve that?
Sagas:
import { take, put,call } from 'redux-saga/effects'; import { takeEvery, delay ,takeLatest} from 'redux-saga'; function fetchData() { return fetch("https://api.github.com/repos/vmg/redcarpet/issues?state=closed") .then(res => res.json() ) .then(data => ({ data }) ) .catch(ex => { console.log('parsing failed', ex); return ({ ex }); }); } function* yourSaga(action) { const { data, ex } = yield call(fetchData); if (data) yield put({ type: 'REQUEST_DONE', data }); else yield put({ type: 'REQUEST_FAILED', ex }); } export default function* watchAsync() { yield* takeLatest('BLAH', yourSaga); } export default function* rootSaga() { yield [ watchAsync() ] }
App:
import React, { Component } from 'react'; import { connect } from 'react-redux'; class App extends Component { componentWillMount() { this.props.dispatch({type: 'BLAH'}); } render(){ return (<div> {this.props.exception && <span>exception: {this.props.exception}</span>} Data: {this.props.data.map(e=><div key={e.id}>{e.url}</div>)} </div>); } } export default connect( state =>({ data:state.data , exception:state.exception }))(App);
My target is to make another saga, which I will use in another component, and both to not mess with each other. Does that possible?
-
David Parker over 7 yearsPer your comment on Github here, I've modified your example to show using two different API calls. You should be able to expand upon that to make it work: webpackbin.com/VkdjuU02Z
-
-
IntoTheDeep over 7 yearsshould I include anything here? export default connect( state =>({ data:state.data , exception:state.exception }))(App);
-
IntoTheDeep over 7 yearsAnd how to define in component itself which saga properties it must get?
-
yjcxy12 over 7 yearsNo, components are completely separated from sagas. You dispatch actions in components, sagas intercepts certain actions (using
take
). A bit similar to reducers. -
agriboz over 6 yearsthat is very helpful :)
-
pourmesomecode over 5 yearsWhen reading the api docs it says that the
all
method is similar toPromise#all
. Here's quote "Creates an Effect description that instructs the middleware to run multiple Effects in parallel and wait for all of them to complete". Is this a different method? Should I be running theall
method if i just have a bunch of different saga's? Exporting a list ofyield takeLatest()
or anall([ yield takeLatest() ])
-
bigmadwolf about 5 yearscould it better to use spawn here? is there any reason to keep them linked to the root saga?
-
dosentmatter almost 5 years@bigmadwolf, if you want the rootSaga to terminate if a single child crashes. It depends on your use case - more about that here. Also, explicitly yielding
all
is better since yielding array will be deprecated. -
Muhammad Husein over 4 years@yjcxy12 don't use fork, use spawn instead, ref: redux-saga.js.org/docs/advanced/RootSaga.html
-
Vinoth about 4 yearsWorking fine for me