# @xstate/svelte
这些 XState v4 文档不再维护
XState v5 现已推出!阅读有关 XState v5 的更多信息 (opens new window) 和 查看 XState v5 文档 (opens new window)。
¥XState v5 is out now! Read more about XState v5 (opens new window) and check out the XState v5 docs (opens new window).
@xstate/svelte package (opens new window) 包含将 XState (opens new window) 与 Svelte (opens new window) 结合使用的实用程序。
¥The @xstate/svelte package (opens new window) contains utilities for using XState (opens new window) with Svelte (opens new window).
# 快速开始
¥Quick Start
安装
xstate
和@xstate/svelte
:¥Install
xstate
and@xstate/svelte
:
npm i xstate @xstate/svelte
通过 CDN
¥Via CDN
<script src="https://unpkg.com/@xstate/svelte/dist/xstate-svelte.min.js"></script>
通过使用全局变量 XStateSvelte
¥By using the global variable XStateSvelte
导入
useMachine
¥Import
useMachine
<script>
import { useMachine } from '@xstate/svelte';
import { createMachine } from 'xstate';
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: {
on: { TOGGLE: 'active' }
},
active: {
on: { TOGGLE: 'inactive' }
}
}
});
const { state, send } = useMachine(toggleMachine);
</script>
<button on:click={() => send('TOGGLE')}>
{$state.value === 'inactive'
? 'Click to activate'
: 'Active! Click to deactivate'}
</button>
# API
# useMachine(machine, options?)
解释给定 machine
并启动在组件生命周期内运行的服务的函数。
¥A function that interprets the given machine
and starts a service that runs for the lifetime of the component.
参数
¥Arguments
machine
- 一个 XState 机器 (opens new window)。¥
machine
- An XState machine (opens new window).options
(可选) - 解释器选项 (opens new window) 或以下机器配置选项之一:guards
、actions
、activities
、services
、delays
、immediate
、context
或state
。¥
options
(optional) - Interpreter options (opens new window) OR one of the following Machine Config options:guards
,actions
,activities
,services
,delays
,immediate
,context
, orstate
.
返回 { state, send, service}
:
¥Returns { state, send, service}
:
state
- Svelte 存储 (opens new window) 将机器的当前状态表示为 XStateState
对象。你应该通过前缀$
(即$state
)来引用存储值。¥
state
- A Svelte store (opens new window) representing the current state of the machine as an XStateState
object. You should reference the store value by prefixing with$
i.e.$state
.send
- 将事件发送到正在运行的服务的函数。¥
send
- A function that sends events to the running service.service
- 创建的服务。¥
service
- The created service.
# useSelector(actor, selector, compare?, getSnapshot?)
返回 Svelte 存储 (opens new window) 的函数,代表从 actor
(例如服务)的快照中选择的值。仅当所选值发生变化时才会更新存储,这由可选的 compare
函数确定。
¥A function that returns Svelte store (opens new window) representing the selected value from the snapshot of an actor
, such as a service. The store will only be updated when the selected value changes, as determined by the optional compare
function.
参数
¥Arguments
actor
- 包含.send(...)
和.subscribe(...)
方法的服务或类似参与者的对象。¥
actor
- a service or an actor-like object that contains.send(...)
and.subscribe(...)
methods.selector
- 一个函数,它将角色的 "当前状态"(快照)作为参数并返回所需的选定值。¥
selector
- a function that takes in an actor's "current state" (snapshot) as an argument and returns the desired selected value.compare
(可选) - 确定当前选择的值是否与先前选择的值相同的函数。¥
compare
(optional) - a function that determines if the current selected value is the same as the previous selected value.
示例
¥Example
<script lang="ts">
import { interpret } from 'xstate';
import { createModel } from 'xstate/lib/model';
import { useSelector } from '../src';
const model = createModel(
{
count: 0,
anotherCount: 0
},
{
events: {
INCREMENT: () => ({}),
INCREMENT_ANOTHER: () => ({})
}
}
);
const machine = model.createMachine({
initial: 'idle',
context: model.initialContext,
states: {
idle: {
on: {
INCREMENT: {
actions: model.assign({ count: ({ count }) => count + 1 })
},
INCREMENT_ANOTHER: {
actions: model.assign({
anotherCount: ({ anotherCount }) => anotherCount + 1
})
}
}
}
}
});
const service = interpret(machine).start();
const count = useSelector(service, (state) => state.context.count);
let withSelector = 0;
$: $count && withSelector++;
let withoutSelector = 0;
$: $service.context.count && withoutSelector++;
</script>
<button data-testid="count" on:click={() => service.send({type:'INCREMENT'})}
>Increment count</button
>
<button data-testid="another" on:click={() => service.send({type:'INCREMENT_ANOTHER'})}
>Increment another count</button
>
<div data-testid="withSelector">{withSelector}</div>
<div data-testid="withoutSelector">{withoutSelector}</div>
# 配置机器
¥Configuring Machines
可以通过将机器选项作为 useMachine(machine, options)
的第二个参数传递来配置现有机器。
¥Existing machines can be configured by passing the machine options as the 2nd argument of useMachine(machine, options)
.
示例:'fetchData'
服务和 'notifySuccess'
操作都是可配置的:
¥Example: the 'fetchData'
service and 'notifySuccess'
action are both configurable:
<script>
import { useMachine } from '@xstate/svelte';
import { createMachine, assign } from 'xstate';
const fetchMachine = createMachine({
id: 'fetch',
initial: 'idle',
context: {
data: undefined,
error: undefined
},
states: {
idle: {
on: { FETCH: 'loading' }
},
loading: {
invoke: {
src: 'fetchData',
onDone: {
target: 'success',
actions: assign({
data: (_, event) => event.data
})
},
onError: {
target: 'failure',
actions: assign({
error: (_, event) => event.data
})
}
}
},
success: {
entry: 'notifySuccess',
type: 'final'
},
failure: {
on: {
RETRY: 'loading'
}
}
}
});
const onResolve = (data) => {
// Do something with data
};
const { state, send } = useMachine(fetchMachine, {
actions: {
notifySuccess: (context) => onResolve(context.data)
},
services: {
fetchData: (_, event) =>
fetch(`some/api/${event.query}`).then((res) => res.json())
}
});
</script>
{#if $state.value === 'idle'}
<button on:click={() => send({ type: 'FETCH', query: 'something' })}>
Search for something
</button>
{:else if $state.value === 'loading'}
<div>Searching...</div>
{:else if $state.value === 'success'}
<div>Success! Data: {$state.context.data}</div>
{:else if $state.value === 'failure'}
<p>{$state.context.error.message}</p>
<button on:click={() => send('RETRY')}>Retry</button>
{/if}
# 匹配状态
¥Matching States
当使用 hierarchical (opens new window) 和 parallel (opens new window) 机器时,状态值将是对象,而不是字符串。在这种情况下,最好使用 state.matches(...)
(opens new window)。
¥When using hierarchical (opens new window) and parallel (opens new window) machines, the state values will be objects, not strings. In this case, it is best to use state.matches(...)
(opens new window).
{#if $state.matches('idle')} // {:else if $state.matches({ loading: 'user' })} // {:else if $state.matches({ loading: 'friends' })} // {/if}
# 持续和再水化状态
¥Persisted and Rehydrated State
你可以通过 options.state
使用 useMachine(...)
保持并补充状态:
¥You can persist and rehydrate state with useMachine(...)
via options.state
:
// Get the persisted state config object from somewhere, e.g. localStorage
const persistedState = JSON.parse(
localStorage.getItem('some-persisted-state-key')
);
const { state, send } = useMachine(someMachine, {
state: persistedState
});
// state will initially be that persisted state, not the machine's initialState
# 服务
¥Services
XState
服务实现了 Svelte 存储合约 (opens new window)。因此,可以直接访问现有服务和衍生的参与者,并通过在服务名称前添加 $
前缀来自动处理订阅。
¥XState
services implement the Svelte store contract (opens new window). Existing services and spawned actors can therefore be accessed directly and subscriptions are handled automatically by prefixing the service name with $
.
示例
¥Example
// service.js
import { createMachine, interpret } from 'xstate';
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: {
on: { TOGGLE: 'active' }
},
active: {
on: { TOGGLE: 'inactive' }
}
}
});
export const toggleService = interpret(toggleMachine).start();
// App.svelte
<script>
import { toggleService } from './service';
</script>
<button on:click={() => toggleService.send({type:'TOGGLE'})}>
{$toggleService.value === 'inactive'
? 'Click to activate'
: 'Active! Click to deactivate'}
</button>