noderaider / redux-idle-monitor

A Redux component to schedule events at stages of user idleness across multiple browser tabs.
https://noderaider.github.io/redux-idle-monitor/
MIT License
105 stars 9 forks source link

Uncaught (in promise) Error: idle status delay must be a number type for idleStatus === 'AWAY' #15

Open oliverbienert opened 7 years ago

oliverbienert commented 7 years ago

Hi, I setup redux-idle-monitor as described in the readme. When running it, the above error appears in the console. With developer tools I digged into this:

var delay = dispatch(idleStatusDelay(idleStatus));

However, the returned type is a Promise, not a number. What's wrong here? My action looks:

export const idleStatusDelay = idleStatus => (dispatch, getState) => {
  const exp_delta = getExpirationDelta();
  if(idleStatus === IDLESTATUS_AWAY)
    return 20000;
  if(idleStatus === IDLESTATUS_INACTIVE)
    return exp_delta;
  if(idleStatus === IDLESTATUS_EXPIRED)
    return exp_delta + 1000; // Log them out after another minute after they enter the inactive status
};

Also store configuration is as you described:

import { middleware as idleMiddleware, actions as idleActions } from "../components/redux-idle-monitor"

export default function configureStore(initialState) {
  const middewares = [
    // Add other middleware on this line...
    apiMiddleware,
    // Redux middleware that spits an error on you when you try to mutate your state either inside a dispatch or between dispatches.
    reduxImmutableStateInvariant(),

    // thunk middleware can also accept an extra argument to be passed to each thunk action
    // https://github.com/gaearon/redux-thunk#injecting-a-custom-argument
    thunkMiddleware,
    idleMiddleware
  ];

  const store = createStore(rootReducer, initialState, compose(
    applyMiddleware(...middewares),
    window.devToolsExtension ? window.devToolsExtension() : f => f // add support for Redux dev tools
    )
  );

  let currentIsAuthorized = null;

  store.subscribe(() => {
    let previousIsAuthorized = currentIsAuthorized;
    let state = store.getState();
    currentIsAuthorized = state.auth.get("isAuthenticated");
    if(currentIsAuthorized !== previousIsAuthorized)
      store.dispatch((currentIsAuthorized ? idleActions.start : idleActions.stop)())
  });
oliverbienert commented 7 years ago

Oh, I see, you do not use redux-thunk package, instead redux-middleware is your own library, which also provides a thunk component. But there you write: Disclaimer: This library is in early development alongside redux-addons. It will be changing rapidly and is not ready for production use.

Nevertheless, I changed store configuration exactly like in your example but don't get it running:

Can you help out? What wrong here?

cchamberlain commented 7 years ago

Can you modify your idleStatusDelay expression to look like the following:

export const idleStatusDelay = idleStatus => (dispatch, getState) => {
  const exp_delta = getExpirationDelta();
  if(typeof exp_delta !== "number")
    throw new Error("exp_delta must be a number, received: " + typeof exp_delta);
  if(idleStatus === IDLESTATUS_AWAY)
    return 20000;
  if(idleStatus === IDLESTATUS_INACTIVE)
    return exp_delta;
  if(idleStatus === IDLESTATUS_EXPIRED)
    return exp_delta + 1000; // Log them out after another minute after they enter the inactive status
  throw new Error("Unhandled status type: " + idleStatus);
};
oliverbienert commented 7 years ago

Hi, first I apologize if my posts sounded a bit offensive, that was not my intention. Quite sure the mistake is at my site. My idleStatusDelay constant now looks so:

export const idleStatusDelay = idleStatus => () => {
  if(idleStatus === IDLESTATUS_AWAY)
    return 20000;
  if(idleStatus === IDLESTATUS_INACTIVE)
    return 60000;
  if(idleStatus === IDLESTATUS_EXPIRED)
    return 120000;
};

Still I have these errors, always:


browser.js:40 Uncaught (in promise) Error: idle status delay must be a number type for idleStatus === 'AWAY'
    at invariant (http://localhost:3000/bundle.js:6307:15)

which in your code (middleware.js) happens here:

        var scheduleTransition = function scheduleTransition(idleStatus) {
          clearTimeout(nextTimeoutID);
          var delay = dispatch(idleStatusDelay(idleStatus));
          (0, _invariant2.default)(delay, 'must return an idle status delay for idleStatus === \'' + idleStatus + '\'');
          (0, _invariant2.default)(typeof delay === 'number', 'idle status delay must be a number type for idleStatus === \'' + idleStatus + '\'');

And the system does not get idle. Never :-( What else could I do to track this down? Regards Oliver

cchamberlain commented 7 years ago

@oliverbienert sorry for slow replies, it's a busy week. I believe that error should only occur if your idleStatusDelay function is not returning a number for some value that it's passed. Making a mental note to publish a new version that makes it more clear when not returning a number from it.

I believe either throwing an error when the idleStatus received doesn't match any of your conditions OR returning a default number would fix your issue. Not returning anything from your function opens the door for it to return undefined which is likely what's going on:

export const idleStatusDelay = idleStatus => () => {
  if(idleStatus === IDLESTATUS_AWAY)
    return 20000;
  if(idleStatus === IDLESTATUS_INACTIVE)
    return 60000;
  if(idleStatus === IDLESTATUS_EXPIRED)
    return 120000;
  // optionally return a default if its not any of those statuses:
  //return 20000;
 // OR (better approach to pinpoint the status not handled)

  throw new Error(`idleStatusDelay must return a number but received unknown idleStatus: ${idleStatus}`);
};