[XState] Guarded Transitions

Garuded Transitions, it prevents the state goes from current sate to its target state is condition is falsy.

const machine = createMachine(
  {
    initial: "idle",
    context: {
      x: 0,
      y: 0,
      dx: 0,
      dy: 0,
      px: 0,
      py: 0,
      drags: 0,
    },
    states: {
      idle: {
        on: {
          mousedown:{
            cond: "noMoreThanFiveTimes",
            actions: assignPoint,
            target: "dragging",
          },
        },
      },
      dragging: {
        entry: countDrags,
        on: {
          mousemove: {
            actions: assignDelta,
          },
          mouseup: {
            actions: [assignPosition],
            target: "idle",
          },
          "keyup.escape": {
            target: "idle",
            actions: resetPosition,
          },
        },
      },
    },
  },
  {
    guards: {
      noMoreThanFiveTimes: (context) => {
        return context.drags >= 5 ? false : true;
      },
    },
  }
);

In the code, users cannot drag more than 5 times. So it preventing going to 'dragging' state by 'cond: "noMoreThanFiveTimes"'.

So if we cannot go 'dragging' state after five times drags... what should we do then?

We can introduce a final state "draggedOut":

const machine = createMachine(
  {
    initial: "idle",
    context: {
      x: 0,
      y: 0,
      dx: 0,
      dy: 0,
      px: 0,
      py: 0,
      drags: 0,
    },
    states: {
      idle: {
        on: {
          // if use Array with cond,
          // for first cond which is false
          // then it continue to second state 'draggedOut'
          mousedown: [
            {
              cond: "noMoreThanFiveTimes",
              actions: assignPoint,
              target: "dragging",
            },
            {
              target: "draggedOut",
            },
          ],
        },
      },
      draggedOut: {
        type: "final",
      },
      dragging: {
        entry: countDrags,
        on: {
          mousemove: {
            actions: assignDelta,
          },
          mouseup: {
            actions: [assignPosition],
            target: "idle",
          },
          "keyup.escape": {
            target: "idle",
            actions: resetPosition,
          },
        },
      },
    },
  },
  {
    guards: {
      noMoreThanFiveTimes: (context) => {
        return context.drags >= 5 ? false : true;
      },
    },
  }
);

So in 'mousedown' event, we use 'Array' type, so it try first target 'dragging' with condition. If the condition is false, then it will try second target 'draggedOut' which is our final state.

原文地址:https://www.cnblogs.com/Answer1215/p/13363059.html