30

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?

IntoTheDeep
  • 4,027
  • 15
  • 39
  • 84
  • Per your comment on Github [here](https://github.com/yelouafi/redux-saga/issues/178#issuecomment-249249953), I've modified your example to show using two different API calls. You should be able to expand upon that to make it work: http://www.webpackbin.com/VkdjuU02Z – David Parker Sep 24 '16 at 13:58

4 Answers4

33

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)
Robin Wieruch
  • 14,900
  • 10
  • 82
  • 107
  • 1
    that is very helpful :) – agriboz Oct 19 '17 at 13:50
  • When reading the api docs it says that the `all` method is similar to `Promise#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 the `all` method if i just have a bunch of different saga's? Exporting a list of `yield takeLatest()` or an `all([ yield takeLatest() ])` – pourmesomecode Jan 14 '19 at 11:14
26

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)
yjcxy12
  • 1,841
  • 1
  • 14
  • 13
  • should I include anything here? export default connect( state =>({ data:state.data , exception:state.exception }))(App); – IntoTheDeep Sep 23 '16 at 20:28
  • And how to define in component itself which saga properties it must get? – IntoTheDeep Sep 23 '16 at 20:31
  • No, components are completely separated from sagas. You dispatch actions in components, sagas intercepts certain actions (using `take`). A bit similar to reducers. – yjcxy12 Sep 24 '16 at 07:31
  • could it better to use spawn here? is there any reason to keep them linked to the root saga? – bigmadwolf Mar 12 '19 at 11:04
  • 1
    @bigmadwolf, if you want the rootSaga to terminate if a single child crashes. It depends on your use case - [more about that here](https://stackoverflow.com/questions/39438005/what-is-the-idiomatic-way-of-starting-rootsaga). Also, explicitly yielding `all` is better since [yielding array will be deprecated](https://github.com/redux-saga/redux-saga/issues/1073). – dosentmatter Jul 15 '19 at 07:45
  • @yjcxy12 don't use fork, use spawn instead, ref: https://redux-saga.js.org/docs/advanced/RootSaga.html – Muhammad Husein Jan 03 '20 at 08:17
7

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

Alex Baulch
  • 751
  • 1
  • 11
  • 24
faithfull
  • 431
  • 6
  • 8
0

As best practice first of all you should create API files that have all the API calls you would like to have. then imported the API you need right in the saga you need to work on then use the same saga for multiple tasks. Then after doing that you should create rootSaga which handles all the saga as guys answered for you already to fork each of your sagas and use All in an array then you're done(the best practice because will show you a lot of fields that were a bit blurry as the flow of redux-saga ...)