question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Sagas started with runSaga can't take actions from Saga started with the middleware

See original GitHub issue

Let’s say I have 2 sagas:

  1. simple api saga that was provided to middleware:
function* apiSaga(getState){
   while(true){
      const action  = yield take('API')
      const { result, error } = yield call(requestApiService, action)
      const [reqType, successType, failType ] = action.types

      yield put({ type: reqType, action })
      if(error) {
         yield put({ type: failType, error })
      } else {
         yield put({ type: successType, result})
      }
   }
}
  1. another saga, that I want to call with runSaga method:
function* routeResolveSaga(getState){
   yield put({ type: 'API', ..... types: ['ACTION_REQUEST', 'ACTION_SUCCESS', 'ACTION_FAIL'] })
   yield take(['ACTION_SUCCESS', 'ACTION_FAIL'])
}

When I call

runSaga(function*(getState){ 
  yield call(routeResolveSaga, getState) 
}(store.getState), storeIO(store))

apiSaga takes API action, after request is puts new action ACTION_SUCCESS or ACTION_FAIL, routeResolveSaga is waiting to take it, but nothing happens.

Maybe I have missed something?

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:15 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
butchmarshallcommented, Apr 18, 2018

I just put together a minimal example - the kicker… it works as expected! I’ll keep investigating as to why it doesn’t work in my full react app.

In my full app if i don’t “fork” it works. I think i’ll just not fork.

import fetch from 'node-fetch';
import {createStore, applyMiddleware, compose, combineReducers} from "redux";
import createSagaMiddleware, { delay, END } from 'redux-saga';
import { apiMiddleware,CALL_API } from 'redux-api-middleware';
import { all, race, take, put, call, fork, select, takeEvery, takeLatest, takeFirst, actionChannel, cancelled, throttle } from 'redux-saga/effects';

// Action

function createAction() {
	return {
		[CALL_API]: {
			endpoint: '/create',
			fetch: () => {
				return fetch("https://www.google.com");
			},
			method: 'GET',
			body: {},
			types: [
				{
					type: "CREATING",
					payload: {some_data_for_ui_update:1}
				},
				"CREATED",
				"CREATE_FAILED",
			],
		}
	};
}

// Saga

function * createActionResource(data) {
	yield put(createAction());
	yield call(delay,3000);
}


function * createActionSaga(action) {
	yield fork(createActionResource, {});
	//yield put(createAction());
console.log("OK WAITING FOR RACE");
	const response = yield race({
		success: take("CREATED"),
		fail: take("CREATE_FAILED"),
	});

	console.log("ANTYHING AFTER FORK???", response);
}

export function* watchCreateAction() {
	yield takeEvery("CREATE_ACTION", createActionSaga);
}

function * rootSaga() {
	yield all([
		watchCreateAction(),
	]);
}

// Reducer

const reducer = (state = {}, {type, payload}) => {
	console.log("in reducer:", type, payload);

	return state;
}

const rootReducer = combineReducers({
    reducer,
});

// Store

const sagaMiddleware = createSagaMiddleware();

const middlewares = [
	apiMiddleware,
	sagaMiddleware,
];
const middlewareEnhancer = applyMiddleware(...middlewares);

const storeEnhancers = [middlewareEnhancer];

const composedEnhancer = compose(...storeEnhancers);

const store = createStore(
	rootReducer,
	undefined,
	composedEnhancer
);

store.runSaga = sagaMiddleware.run;
store.runSaga(rootSaga);


store.dispatch({
	type: "CREATE_ACTION"
});
0reactions
ProphetDanielcommented, Aug 18, 2018

Sagas started with runSaga can’t take actions from Saga started with the middleware

In the other hand, according to @butchmarshall 's example, reducers are able to take actions from the sagas started with the middleware.

So my workaround to this problem is to dispatch a new event triggered by the reducer capture so that the sagas started with runSaga can properly take them indirectly in a two step process. Just make sure this anti-pattern is avoided.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Troubleshooting | Redux-Saga
It will put the application into an infinite loop because take() only creates a description of the effect. Unless you yield it for...
Read more >
redux-saga cannot catch actions dispatched by store enhancers
run(sagas); ). From redux-saga docs it seems that saga must be run after applyMiddleware, so I cannot make saga run before enhancer. Is...
Read more >
Redux Toolkit's new listener middleware vs. Redux-Saga
Redux Toolkit's new listener middleware is a great alternative to Redux Saga, with a few caveats - learn all about it in this...
Read more >
Using runSaga | redux-saga
Dynamically starting Sagas with runSaga. The runSaga function allows starting sagas outside the Redux middleware environment. It also allows you to hook up ......
Read more >
Redux Saga Testing Using Runsaga Not Updating The State
From the saga examples it looks like they all use a Sagas started by runSaga can't see actions from sagas started by the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found