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.

handleTransition's setState batched, actions not called

See original GitHub issue

I’m using withStatechart and this parallel machine (simplified):

export default {
  key: 'controller',
  parallel: true,
  states: {
    NormalizeItems: {
      initial: 'Normalizing',
      states: {
        Normalizing: {
          on: {
            NORMALIZE_SUCCESS: {
              Normalizing: {
                actions: ['startSessionSocket', 'subscribeItems'],
              },
            },
          },
        },
      },
    },
    SessionSocket: {
      initial: 'Disconnected',
      states: {
        Disconnected: {
          on: {
            START_SESSION_SOCKET: {
              Connected: {
                actions: ['joinSessionSocket'],
              },
            },
          },
        },
        Connected: {
          on: {
            SESSION_SOCKET_SUBSCRIBE: {
              Connected: {
                actions: ['emitSubscribeItems'],
              },
            },
          },
        },
      },
    },
  },
}

At some point, the first “child machine” calls startSessionSocket and subscribeItems, which look like this:

startSessionSocket = () => {
  this.props.transition('START_SESSION_SOCKET')
}

subscribeItems = () => {
  this.props.transition('SESSION_SOCKET_SUBSCRIBE')
}

This triggers the second child machine and should also call joinSessionSocket and emitSubscribeItems. However, only the second action (emitSubscribeItems) is called.

I suspect that’s because I call one transition after the other, sync, and setState gets batched by React here. And since runActionMethods is called by componentDidUpdate, the joinSessionSocket action is not called.

I understand you may not see this as a bug, and I could possibly fix this by grouping this to one transition / one action, but this happens in more places in the app and I figured such a fix doesn’t always result in maintainable code.

BTW: This component is one of the many “units” I have, and it has no UI. So I don’t care much about re-renders.

TL;DR: Action methods are called in componentDidUpdate. When React happens to batch multiple setState() calls in handleTransition, the machine itself is in the correct state (thanks to setState(prevState => ...)), but only actions from the last transition are called.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:26 (13 by maintainers)

github_iconTop GitHub Comments

2reactions
MicheleBertolicommented, May 7, 2018

Thank you very much for your comments @lnogol @oliverhausler.

I closed this issue with a commit that prevents to fire consecutive transitions and enforces the intended behaviour.

For example, the following handler:

handleClick = () => {
  this.props.transition('FOO')
  this.props.transition('BAR')
}

throws this error:

screen shot 2018-05-07 at 5 59 28 pm

I’m not making any assumption but I couldn’t find a use-case where firing multiple tranisitions in the same “render” was the only option.

Joao, on Twitter, expressed a similar opinion:

Well, if someone’s doing consecutive transitions they need to step back and stop for a bit to think how state machines work.

Also, I disagree that “Using it for business logic like automata simply is an approach that doesn’t work”, I just think we need to find the correct approach to get the best of both worlds. For example, when I started using Flux I hated the “cannot dispatch in the middle of a dispatch” error until I learned how to use it properly.

In any case, feel free to reopen this issue and most importantly to propose solutions and/or submit PRs, I’ll be more than happy to discuss and review the code.

I will keep on thinking about this as well - it’s just that I couldn’t find a simple/clean solution and often, when this happens, it means I’m trying to solve the wrong problem : )

0reactions
MicheleBertolicommented, Dec 2, 2018

Thanks for your comment, @larsbuch. Would you be able to provide more information about your “concurrency” problem?

Read more comments on GitHub >

github_iconTop Results From Across the Web

React not batching your setState updates? Here's what you ...
React not batching your setState updates? Here's what you can do about it. Say you're calling two state update functions, one after the...
Read more >
Why are consecutive setState calls in async functions not ...
This issue discusses when setState is batched and when it isn't: ... React wraps your event handlers in a call to unstable_batchedUpdates(), ...
Read more >
React state batch updating - reduce re-renders | The Startup
We change the state by calling setState or using useState . These changes cause parts of the component to re-render, and possibly to...
Read more >
React hooks gotchas: setState in async useEffect
When a useEffect() does not trigger any async action, the setState s are batched properly. The solution: Grouping states that go together. To...
Read more >
Why React doesn't update state immediately - LogRocket Blog
For this reason, React batches state updates. No matter how many setState() calls are in the handleClick event handler, they will produce ...
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