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

After actions don't trigger when rehydrating state using State.from #294

Closed
Dirklectisch opened this issue Jan 4, 2019 · 3 comments
Closed
Labels

Comments

@Dirklectisch
Copy link

Bug or feature request?

Bug

Description:

I am trying to resume an interpreter using a state as the argument when starting. However the after actions on that state do not trigger leaving my interpreter stuck in that state.

(Bug) Expected result:

State transition after the specified time.

(Bug) Actual result:

Interpreter waiting for further input.

(Bug) Potential fix:

I haven't had a chance to look at the source code for Xstate, but I did find a very dirty workaround. I added an extra loading state to my machine that I will load up first and then transition into the actual state I want to restore to. This way everything works as expected.

Link to reproduction or proof-of-concept:

Here's a code sandbox that illustrates the problem:

Edit xstate state after actions on rehydrate

Here's the actual code of my minimal example for easy reference:

import { Machine, State } from "xstate";
import { interpret } from "xstate/lib/interpreter";

const stateChart = {
  context: {},
  states: {
    ping: {
      after: {
        1000: "pong"
      }
    },
    pong: {
      after: {
        1000: "ping"
      }
    }
  }
};

const machine = Machine(stateChart);
const service = interpret(machine);
service.onTransition(current => console.log(current.value));

const initState = State.from("ping", {});
service.start(initState);
@davidkpiano
Copy link
Member

When a delayed transition occurs, a special action is internally sent to send a timer event after the specified delay.

However, when you specify the initState, you aren't specifying any actions. To fix this:

  1. Define an initial state (which you should do anyway)
  2. Use the machine.initialState as the initial state (this is the default when calling service.start()).

The modified code below works:

import { Machine, State } from "xstate";
import { interpret } from "xstate/lib/interpreter";

const stateChart = {
  context: {},
  initial: "ping",
  states: {
    ping: {
      after: {
        1000: "pong"
      }
    },
    pong: {
      after: {
        1000: "ping"
      }
    }
  }
};

const machine = Machine(stateChart);
const service = interpret(machine);
service.onTransition(current => console.log(current.value));
service.start();

@Dirklectisch
Copy link
Author

Dirklectisch commented Jan 4, 2019

@davidkpiano Sure it works if you don't pass an initial state to the interpreter and set the initial up front. However that wasn't the issue here. I want to be able to enter the state machine with a specific context at any point of the machine when restoring the system. Therefore I'm not using the initial state but State.from.

What if I wanted to start the above machine on the pong state state with an arbitrary context? Now the delayed transition on that wouldn't trigger.

Thanks for your reply!

@davidkpiano
Copy link
Member

What if I wanted to start the above machine on the pong state state with an arbitrary context? Now the delayed transition on that wouldn't trigger.

There's two approaches to this:

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

No branches or pull requests

2 participants