user2465134
user2465134

Reputation: 9773

Watching for a redux-saga action in redux

All of my API calls are handled by redux-sagas. I'm creating a heartbeat modal in my app to detect inactivity. Each time a saga goes off I want to clear my setTimeout so I know that the user is active.

My middleware is a basic one at the moment:

const heartbeatMonitor => store => next => action {
  if (action['@@redux-saga/SAGA_ACTION']) {
    clearTimeout(window.myTimeout);
  }

  window.myTimeout = window.setTimeout(function() {
    // send off an action to tell user they are inactive
  }, 100000);
}

It seems like looking for this symbol, @@redux-saga/SAGA_ACTION, is the only way to tell if the action is a saga. I see that redux-sagas has a createSagaMiddleware(options) and I tried using effectMiddlewares but it doesn't seem like you have access to the dispatch method in there so I can't send off a new actions.

Upvotes: 0

Views: 1003

Answers (1)

Leo
Leo

Reputation: 1800

but it doesn't seem like you have access to the dispatch method in there so I can't send off a new actions.

Not sure whether this is the kind of solution you wanted, but you do have access to the dispatch method where your comment // send off an action to tell user they are inactive is located in your code snippet, as it is exposed by the store object. (this is documented in the Store Methods Section of the store in the redux docs)

Therefore something like the following should satisfy your case:

const heartbeatMonitor => store => next => action {
  if (action['@@redux-saga/SAGA_ACTION']) {
    clearTimeout(window.myTimeout);
  }

  const { dispatch } = store;

  window.myTimeout = window.setTimeout(() => {
    dispatch({ type: "USER_INACTIVE" });
  }, 100000);
}

Note: I would probably implement this differently (using redux-sagas effects) Maybe this is an option for you too:

Example Saga

import { put, delay } from "redux-saga/effects";

function* inactiveSaga() {
  yield delay(100000);
  yield put({ type: "USER_INACTIVE" })
}

Example Integration of saga above:

(add the following in your root saga)

//import { takeLatest } from "redux-saga/effects";
    takeLatest(() => true, inactiveSaga)

Explanation: Every action will trigger the inactiveSaga (cause () => true). The inactiveSaga will wait 100000ms before dispatching the "inactive action". If there is a new action within this waiting time the previous execution of the inactiveSaga will be canceled (cause takeLatest, see redux-saga effect docs for takeLatest) and started from the beginning again. (Therefore no "inactive action" will be sent and the inactiveSaga will start to wait for these 100000ms again, before being cancelled or completing the delay and dispatching the "inactive action")

Upvotes: 2

Related Questions