是否可以在不使用当前状态的条件语句的情况下使用状态机?

Posted

技术标签:

【中文标题】是否可以在不使用当前状态的条件语句的情况下使用状态机?【英文标题】:Is it posible to use a State Machine without using Conditional Statements on the Current State? 【发布时间】:2021-11-01 18:53:47 【问题描述】:

我想使用当前状态映射到当前屏幕的状态机。我正在使用svelte 和xstate。 以字符串为类型的示例: App.svelte

<script>
    import  interpret  from "xstate";
    import  toggleMachine  from "./machine";

    const toggleService = interpret(toggleMachine).start();
</script>

<button on:click=() => toggleService.send("TOGGLE")>
    <p>$toggleService.value</p>
</button>

machine.js

import  createMachine  from 'xstate';

// This machine is completely decoupled from Svelte
export const toggleMachine = createMachine(
    id: 'toggle',
    initial: 'LOGIN',
    states: 
        LOBBY: 
            on:  TOGGLE: 'LOGIN' 
        ,
        LOGIN: 
            on:  TOGGLE: 'LOBBY' 
        
    
);

如何用细长的组件而不是字符串来做同样的事情? 而不是&lt;p&gt;$toggleService.value&lt;/p&gt; 这样的&lt;$toggleService.value /&gt;

编辑:我尝试了什么:

创建 Lobby 和 Login svelte 组件 Login.svelte
<script lang="ts">
</script>

<main>
    <h1>Login</h1>
</main>

<style>
</style>

Lobby.svelte

<script lang="ts">
</script>

<main>
    <h1>Lobby</h1>
</main>

<style>
</style>

在 machine.js 中使用它们
import  createMachine  from 'xstate';
import Login from './Login.svelte'
import Lobby from './Lobby.svelte'
// This machine is completely decoupled from Svelte
export const toggleMachine = createMachine(
    id: 'toggle',
    initial: Login,
    states: 
        Login: 
            on:  TOGGLE: Lobby 
        ,
        Lobby: 
            on:  TOGGLE: Login 
        
    
);
在 App.svelte 中使用状态机 App.svelte
<script>
    import  interpret  from "xstate";
    import  toggleMachine  from "./machine";

    const toggleService = interpret(toggleMachine).start();
</script>

<button on:click=() => toggleService.send("TOGGLE")>
    <$toggleService.value />
</button>

我得到错误:

[!] (plugin svelte) ParseError: Expected valid tag name
src/App.svelte
 7: 
 8: <button on:click=() => toggleService.send("TOGGLE")>
 9:   <$toggleService.value />
       ^
10: </button>
ParseError: Expected valid tag name
    at error (/home/walde/projects/svelte/xstate/node_modules/svelte/src/compiler/utils/error.ts:25:16)
    at Parser$1.error (/home/walde/projects/svelte/xstate/node_modules/svelte/src/compiler/parse/index.ts:101:3)
    at read_tag_name (/home/walde/projects/svelte/xstate/node_modules/svelte/src/compiler/parse/state/tag.ts:267:10)
    at tag (/home/walde/projects/svelte/xstate/node_modules/svelte/src/compiler/parse/state/tag.ts:77:15)
    at new Parser$1 (/home/walde/projects/svelte/xstate/node_modules/svelte/src/compiler/parse/index.ts:53:12)
    at parse (/home/walde/projects/svelte/xstate/node_modules/svelte/src/compiler/parse/index.ts:218:17)
    at compile (/home/walde/projects/svelte/xstate/node_modules/svelte/src/compiler/compile/index.ts:93:14)
    at Object.transform (/home/walde/projects/svelte/xstate/node_modules/rollup-plugin-svelte/index.js:111:21)
    at /home/walde/projects/svelte/xstate/node_modules/rollup/dist/shared/rollup.js:20218:25

【问题讨论】:

【参考方案1】:

我不能代表 xstate 部分,但最后一个 sn-p 肯定不起作用。您不能像这样动态声明标签。但是您可以为此使用特殊的&lt;svelte:component&gt; 元素:

<script>
    import  interpret  from "xstate";
    import  toggleMachine  from "./machine";

    const toggleService = interpret(toggleMachine).start();
</script>

<button on:click=() => toggleService.send("TOGGLE")>
    Toggle me
</button>
<svelte:component this=$toggleService.value />

文档:https://svelte.dev/docs#svelte_component

【讨论】:

【参考方案2】:

感谢 dummdidumm 帮助解决纤细部分的问题。

svelte 和 xstate 不写条件语句的问题的完整解决方法是:

将组件绑定到状态机的上下文
<svelte:component this=$toggleService.context.component />
将进入时的状态机上下文更改为新状态,使其与当前状态匹配。
        Login: 
            on:  TOGGLE: "Lobby" ,
            entry: assign( component: (ctx) => ctx.component = Login ),
        

完整的工作示例: App.svelte

<script>
    import  interpret  from "xstate";
    import  toggleMachine  from "./machine";
    const toggleService = interpret(toggleMachine).start();
</script>

<button on:click=() => toggleService.send("TOGGLE")>
    $toggleService.value
</button>
<svelte:component this=$toggleService.context.component />

Lobby.svelte

<script lang="ts">
</script>
<main>
    <h1>SVELTE Lobby</h1>
</main>
<style>
</style>

Login.svelte

<script lang="ts">
</script>
<main>
    <h1>SVELTE Login</h1>
</main>
<style>
</style>

machine.js

import  createMachine, assign  from 'xstate';
import Login from './Login.svelte'
import Lobby from './Lobby.svelte'
export const toggleMachine = createMachine(
    id: 'toggle',
    initial: "Login",
    context: 
        component: Lobby
    ,
    states: 
        Login: 
            on:  TOGGLE: "Lobby" ,
            entry: assign( component: (ctx) => ctx.component = Login ),
        ,
        Lobby: 
            on:  TOGGLE: "Login" ,
            entry: assign( component: (ctx) => ctx.component = Lobby ),
        
    
);

【讨论】:

以上是关于是否可以在不使用当前状态的条件语句的情况下使用状态机?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不参考 NSEvent 的情况下在 Objective-C 中获取键盘状态

是否可以在不隐藏键盘的情况下使 UITextView 处于非活动状态(可编辑 = 否)?

如何在不重置其当前状态的情况下从一个视图控制器到自身进行转场?

Apache Flink-在不使用广播状态的情况下更新操作员中的配置

在不知道当前视图状态的情况下实现 openURL

是否有另一种方法可以在不使用 if 语句的情况下有条件地增加数组值? C++