Easy-peasy: listeners being stepped on by thunks

Created on 24 Apr 2019  路  10Comments  路  Source: ctrlplusb/easy-peasy

Hi! I just upgraded to v2. I have a loadingModel which is just an object of things than can be loading, and their boolean values.

example:

const loadingModel = {
  set: action((state, { type, status }) => {
    state[type] = status;
  }),
  current: {},
  listeners: listen(on => {
    on(
      userModel.requested,
      action(state => {
        state.current.user = true;
      }),
    );
    on(
      userModel.received,
      action(state => {
        state.current.user = false;
      }),
    );
    on(
      userModel.rejected,
      action(state => {
        state.current.user = false;
      }),
    );
  },
};

userModel.reqested is a thunk, userModel.received and userModel.rejected are plain actions.

Currently, this is the flow that is happening:

  1. @thunk.user.requested(started)
  2. state.loading.user = true
  3. @action.user.received
  4. state.loading.user = false
  5. @thunk.user.requested(complete)
  6. state.loading.user = true

what I assume is happening is that the complete thunk is detected by on(userModel.requested).

What's the proper way to handle this kind of pattern? What am I doing wrong?

Thanks!

All 10 comments

Hey @VinSpee;

Are you trying to fire your listener at the start of @thunk.user.requested? i.e. before the thunk gets executed?

@ctrlplusb exactly right.

Ok, yeah, I believe v1 incorrectly fired listeners at the start of the thunk where my intended behaviour with the functionality was to only fire them at a thunk completing without error.

You could emulate the start of the thunk listening, I think, via something similar to:

import { thunkStartName } from 'easy-peasy';

const loadingModel = {
  set: action((state, { type, status }) => {
    state[type] = status;
  }),
  current: {},
  listeners: listen(on => {
    on(
      thunkStartName(userModel.requested),
      action(state => {
        state.current.user = true;
      }),
    );
    ...

That being said I prefer approaching listeners with being reactive, i.e. responding to succeeded thunks/actions.

Perfect. Thanks.

I do find it a bit unexpected that it would fire for both the start and end, should I leave this open or close it?

Oh wait, I didn't catch that. The listener fires for the start and the complete of the thunk? If so that is definitely a bug. It should only fire once on successful completion of the thunk.

I鈥檒l get a minimal reproduction together in a codesandbox.

Ok, correction - I was misinterpreting the output.

What happens is like this:

  • thunk dispatched (user.requested)
  • action user.requested(started) is dispatched
  • on(user.requested) NOT triggered, as you expected
  • action dispatched (user.received)
  • on(user.received) triggered, as expected
  • action user.requested(finished) is dispatched
  • on(user.requested) IS triggered, as you expected.

check the devtools if you care to follow along.

https://p3v438l8lm.codesandbox.io/

So is the best way to manage a loading slice like this to do as you suggested and using thunkStartName and thunkEndName? I'm also wondering now if user.requested should be a thunk at all, or rather just an action which has a listener set up which is responsible for API calls, then dispatches a received action upon successful execution. Thoughts on an implementation like this?

Hey, I personally feel your original implementation is the better approach. You just need to tweak the listeners slightly.

The following approach could work for you:

https://codesandbox.io/s/jv623kql43

Thanks for the help, and explanations! I truly appreciate it and all of your work on easy-peasy.

No problem @VinSpee - it's awesome that you continue to find it useful 鈾ワ笍

Was this page helpful?
0 / 5 - 0 ratings