Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generator with 'takeLatest' - is canceling and debouncing possible? #3

Closed
alp82 opened this issue Nov 10, 2017 · 4 comments
Closed

Comments

@alp82
Copy link

alp82 commented Nov 10, 2017

You showed an example with generators:

const machine = Machine.create('todo-app', {
  state: { name: 'idle', todos: [] },
  transitions: {
    'idle': {
      'fetch todos': function * () {
        yield { name: 'fetching' };

        try {
          const todos = yield call(getTodos, '/api/todos');
        } catch (error) {
          return { name: 'error', error };
        }

        return { name: 'done', todos };
      }
    }
  }
});

If I would perform machine.fetchTodos() twice while the async call is still ongoing, the second one is simply discarded.

  • How to model a machine that cancels the first one and fetches again?
  • How to debounce such executions?
@alp82 alp82 changed the title generator with 'takeLatest' - is canceling or debouncing possible? generator with 'takeLatest' - is canceling and debouncing possible? Nov 10, 2017
@krasimir
Copy link
Owner

I'll try to release a new version these days. Funny enough I hit the same problem. I just needed takeLatest.

@alp82
Copy link
Author

alp82 commented Nov 10, 2017

I just stumbled upon this project due to your great article and this was the first thing that came to my mind when taking a glance at your README.

@krasimir
Copy link
Owner

Yep, that's definitely a valid use case. I'm going to add something which will work like takeLatest.

krasimir pushed a commit that referenced this issue Nov 14, 2017
@krasimir
Copy link
Owner

Ok, just released 3.0.0 version that supports a latest version of the method. So for example if the machine has a fetchTodos method you may use:

machine.fetchTodos.latest();

This will kill a previous call which is still in progress. However, I have to make a note here. Let's see the following redux-saga code:

function test (n) {
  return {
    type: 'TEST',
    n
  };
}
store.runSaga(function * () {
  yield takeLatest('TEST', function * ({ n }) {
    console.log(n);
    setTimeout(() => console.log('you can not stop me'), 2000);
    console.log('promise: ' + (yield call(a, n)));
  });
});
store.runSaga(function *() {
  yield put(test(1));
  yield put(test(2));
});

/*
1 <-- immediately
2 <-- immediately
promise 2 <-- a second later
you can not stop me <-- two seconds later
you can not stop me <-- two seconds later
*/

So we have a saga that waits for an action. Once this action comes we do something (the first console.log) synchronous and then do two other things which are asynchronous. The difference between them is that the first one setTimeout(() => console.log('you can not stop me'), 2000); is not in a control of redux-saga library while the second one is. As we can see from the produced console output we get that first async operation fired no matter what. That is because redux-saga has no idea about this process and can not stop it. It is the same with Stent. As long as the async process is wrapped in a call execution we have .latest working. Otherwise then canceling does not work.

That new version of Stent support takeLatest-ish logic which is fine for cases where we don't bother making the request twice. However if you want to implement a debounce and avoid making multiple requests I'll suggest to do it upfront and not rely on Stent for it. Just debounce the action dispatching.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants