# 状态
¥States
这些 XState v4 文档不再维护
XState v5 现已推出!阅读有关 XState v5 的更多信息 (opens new window)
¥XState v5 is out now! Read more about XState v5 (opens new window)
🆕 了解有关 XState 中的状态 (opens new window) 和 无代码状态介绍 (opens new window) 的更多信息。
¥🆕 Find more about states in XState (opens new window) as well as a no-code introduction to states (opens new window).
状态是系统(例如应用)在特定时间点的抽象表示。要了解更多信息,请阅读 状态图简介中有关状态的部分。
¥A state is an abstract representation of a system (such as an application) at a specific point in time. To learn more, read the section on states in our introduction to statecharts.
# API
机器的当前状态由 State
实例表示:
¥The current state of a machine is represented by a State
instance:
const lightMachine = createMachine({
id: 'light',
initial: 'green',
states: {
green: {
/* ... */
}
// ...
}
});
console.log(lightMachine.initialState);
// State {
// value: 'green',
// actions: [],
// context: undefined,
// // ...
// }
console.log(lightMachine.transition('yellow', { type: 'TIMER' }));
// State {
// value: { red: 'walk' },
// actions: [],
// context: undefined,
// // ...
// }
# 状态定义
¥State definition
State
对象实例是 JSON 可序列化的,并具有以下属性:
¥A State
object instance is JSON-serializable and has the following properties:
value
- 当前状态值(例如,{red: 'walk'}
)¥
value
- the current state value (e.g.,{red: 'walk'}
)context
- 该状态当前的 context¥
context
- the current context of this stateevent
- 触发转换到此状态的事件对象¥
event
- the event object that triggered the transition to this stateactions
- 要执行的 actions 数组¥
actions
- an array of actions to be executedactivities
- 如果活动开始,则映射 activities 到true
;如果活动停止,则映射false
。¥
activities
- a mapping of activities totrue
if the activity started, orfalse
if stopped.history
- 前一个State
实例¥
history
- the previousState
instancemeta
- 在 状态节点 的meta
属性上定义的任何静态元数据¥
meta
- any static meta data defined on themeta
property of the state nodedone
- 该状态是否表示最终状态¥
done
- whether the state indicates a final state
State
对象还包含其他属性,例如 historyValue
、events
、tree
以及其他通常不相关且在内部使用的属性。
¥The State
object also contains other properties such as historyValue
, events
, tree
and others that are generally not relevant and are used internally.
# 状态方法和属性
¥State methods and properties
你可以使用一些有用的方法和属性来获得更好的开发体验:
¥There are some helpful methods and properties you can use for a better development experience:
# state.matches(parentStateValue)
state.matches(parentStateValue)
方法确定当前 state.value
是否是给定 parentStateValue
的子集。该方法确定父状态值是否与状态值“匹配”。例如,假设当前 state.value
为 { red: 'stop' }
:
¥The state.matches(parentStateValue)
method determines whether the current state.value
is a subset of the given parentStateValue
. The method determines if the parent state value “matches” the state value. For example, assuming the current state.value
is { red: 'stop' }
:
console.log(state.value);
// => { red: 'stop' }
console.log(state.matches('red'));
// => true
console.log(state.matches('red.stop'));
// => true
console.log(state.matches({ red: 'stop' }));
// => true
console.log(state.matches('green'));
// => false
提示
如果要匹配多个状态之一,可以在状态值数组上使用 .some()
(opens new window) 来完成此操作:
¥If you want to match one of multiple states, you can use .some()
(opens new window) on an array of state values to accomplish this:
const isMatch = [{ customer: 'deposit' }, { customer: 'withdrawal' }].some(
state.matches
);
# state.nextEvents
state.nextEvents
指定将导致从当前状态转换的下一个事件:
¥state.nextEvents
specifies the next events that will cause a transition from the current state:
const { initialState } = lightMachine;
console.log(initialState.nextEvents);
// => ['TIMER', 'EMERGENCY']
state.nextEvents
对于确定可以采取哪些下一个事件以及在 UI 中表示这些潜在事件(例如启用/禁用某些按钮)非常有用。
¥state.nextEvents
is useful in determining which next events can be taken, and representing these potential events in the UI such as enabling/disabling certain buttons.
# state.changed
state.changed
指定此 state
是否已从先前状态更改。如果出现以下情况,则状态被视为“已更改”:
¥state.changed
specifies if this state
has changed from the previous state. A state is considered “changed” if:
它的值不等于它之前的值,或者:
¥Its value is not equal to its previous value, or:
它有任何新的操作(副作用)要执行。
¥It has any new actions (side-effects) to execute.
初始状态(没有历史记录)将返回 undefined
。
¥An initial state (with no history) will return undefined
.
const { initialState } = lightMachine;
console.log(initialState.changed);
// => undefined
const nextState = lightMachine.transition(initialState, { type: 'TIMER' });
console.log(nextState.changed);
// => true
const unchangedState = lightMachine.transition(nextState, {
type: 'UNKNOWN_EVENT'
});
console.log(unchangedState.changed);
// => false
# state.done
state.done
指定 state
是否是 “最终状态” - 最终状态是指示其机器已达到其最终(终端)状态并且不能再转换到任何其他状态的状态。
¥state.done
specifies whether the state
is a “final state” - a final state is a state that indicates that its machine has reached its final (terminal) state and can no longer transition to any other state.
const answeringMachine = createMachine({
initial: 'unanswered',
states: {
unanswered: {
on: {
ANSWER: { target: 'answered' }
}
},
answered: {
type: 'final'
}
}
});
const { initialState } = answeringMachine;
initialState.done; // false
const answeredState = answeringMachine.transition(initialState, {
type: 'ANSWER'
});
answeredState.done; // true
# state.toStrings()
state.toStrings()
方法返回表示所有状态值路径的字符串数组。例如,假设当前 state.value
为 { red: 'stop' }
:
¥The state.toStrings()
method returns an array of strings that represent all of the state value paths. For example, assuming the current state.value
is { red: 'stop' }
:
console.log(state.value);
// => { red: 'stop' }
console.log(state.toStrings());
// => ['red', 'red.stop']
state.toStrings()
方法对于表示基于字符串的环境中的当前状态非常有用,例如在 CSS 类或数据属性中。
¥The state.toStrings()
method is useful for representing the current state in string-based environments, such as in CSS classes or data-attributes.
# state.children
state.children
是将生成的服务/参与者 ID 映射到其实例的对象。详细信息请参见 📖 参考服务。
¥state.children
is an object mapping spawned service/actor IDs to their instances. See 📖 Referencing Services for more details.
# 使用 state.children
的示例
¥Example using state.children
const machine = createMachine({
// ...
invoke: [
{ id: 'notifier', src: createNotifier },
{ id: 'logger', src: createLogger }
]
// ...
});
const service = invoke(machine)
.onTransition((state) => {
state.children.notifier; // service from createNotifier()
state.children.logger; // service from createLogger()
})
.start();
# state.hasTag(tag)
自 4.19.0 起
¥Since 4.19.0
state.hasTag(tag)
方法确定当前状态配置是否具有带有给定标记的状态节点。
¥The state.hasTag(tag)
method determines whether the current state configuration has a state node with the given tag.
const machine = createMachine({
initial: 'green',
states: {
green: {
tags: 'go' // single tag
},
yellow: {
tags: 'go'
},
red: {
tags: ['stop', 'other'] // multiple tags
}
}
});
例如,如果上面的机器处于 green
或 yellow
状态,则可以使用 state.hasTag('go')
来代替直接使用 state.matches('green') || state.matches('yellow')
来匹配状态:
¥For instance, if the above machine is in the green
or yellow
state, instead of matching the state directly using state.matches('green') || state.matches('yellow')
, it is possible to use state.hasTag('go')
:
const canGo = state.hasTag('go');
// => `true` if in 'green' or 'yellow' state
# state.can(event)
从 4.25.0 开始
¥Since 4.25.0
state.can(event)
方法确定 event
如果发送到解释机是否会导致状态更改。如果发送 event
导致状态发生变化,该方法将返回 true
;否则该方法将返回 false
:
¥The state.can(event)
method determines whether an event
will cause a state change if sent to the interpreted machine. The method will return true
if the state will change due to the event
being sent; otherwise the method will return false
:
const machine = createMachine({
initial: 'inactive',
states: {
inactive: {
on: {
TOGGLE: 'active'
}
},
active: {
on: {
DO_SOMETHING: { actions: ['something'] }
}
}
}
});
const inactiveState = machine.initialState;
inactiveState.can({ type: 'TOGGLE' }); // true
inactiveState.can({ type: 'DO_SOMETHING' }); // false
inactiveState.can({
type: 'DO_SOMETHING',
data: 42
}); // false
const activeState = machine.transition(inactiveState, { type: 'TOGGLE' });
activeState.can({ type: 'TOGGLE' }); // false
activeState.can({ type: 'DO_SOMETHING' }); // true, since an action will be executed
如果 state.changed
是 true
并且满足以下任一条件,则状态被视为“已更改”:
¥A state is considered “changed” if state.changed
is true
and if any of the following are true:
它的
state.value
变化¥its
state.value
changes有新的
state.actions
要执行¥there are new
state.actions
to be executed它的
state.context
发生了变化。¥its
state.context
changes.
警告
state.can(...)
函数还将通过执行转换防护来检查它们。转换守卫应该是纯函数。
¥The state.can(...)
function will also check transition guards by executing them. Transition guards should be pure functions.
# 持续状态
¥Persisting state
如前所述,可以通过将 State
对象序列化为字符串 JSON 格式来持久保存该对象:
¥As mentioned, a State
object can be persisted by serializing it to a string JSON format:
const jsonState = JSON.stringify(currentState);
// Example: persisting to localStorage
try {
localStorage.setItem('app-state', jsonState);
} catch (e) {
// unable to save to localStorage
}
可以使用静态 State.create(...)
方法恢复状态:
¥State can be restored using the static State.create(...)
method:
import { State, interpret } from 'xstate';
import { myMachine } from '../path/to/myMachine';
// Retrieving the state definition from localStorage, if localStorage is empty use machine initial state
const stateDefinition =
JSON.parse(localStorage.getItem('app-state')) || myMachine.initialState;
// Use State.create() to restore state from a plain object
const previousState = State.create(stateDefinition);
然后,你可以通过将 State
传递到解释服务的 .start(...)
方法来从此状态解释机器:
¥You can then interpret the machine from this state by passing the State
into the .start(...)
method of the interpreted service:
// ...
// This will start the service at the specified State
const service = interpret(myMachine).start(previousState);
这还将维护和恢复以前的 历史陈述 并确保 .events
和 .nextEvents
代表正确的值。
¥This will also maintain and restore previous history states and ensures that .events
and .nextEvents
represent the correct values.
# 状态元数据
¥State meta data
元数据是描述任何 状态节点 相关属性的静态数据,可以在状态节点的 .meta
属性上指定:
¥Meta data, which is static data that describes relevant properties of any state node, can be specified on the .meta
property of the state node:
const fetchMachine = createMachine({
id: 'fetch',
initial: 'idle',
states: {
idle: {
on: { FETCH: { target: 'loading' } }
},
loading: {
after: {
3000: 'failure.timeout'
},
on: {
RESOLVE: { target: 'success' },
REJECT: { target: 'failure' },
TIMEOUT: { target: 'failure.timeout' } // manual timeout
},
meta: {
message: 'Loading...'
}
},
success: {
meta: {
message: 'The request succeeded!'
}
},
failure: {
initial: 'rejection',
states: {
rejection: {
meta: {
message: 'The request failed.'
}
},
timeout: {
meta: {
message: 'The request timed out.'
}
}
},
meta: {
alert: 'Uh oh.'
}
}
}
});
机器的当前状态收集所有状态节点的 .meta
数据,用状态值表示,并将它们放在一个对象上,其中:
¥The current state of the machine collects the .meta
data of all of the state nodes, represented by the state value, and places them on an object where:
键是 状态节点 ID
¥The keys are the state node IDs
这些值为状态节点
.meta
值¥The values are the state node
.meta
values
例如,如果上述机器处于 failure.timeout
状态(由 ID 为 "failure"
和 "failure.timeout"
的两个状态节点表示),则 .meta
属性将组合所有 .meta
值,如下所示:
¥For instance, if the above machine is in the failure.timeout
state (which is represented by two state nodes with IDs "failure"
and "failure.timeout"
), the .meta
property will combine all .meta
values as follows:
const failureTimeoutState = fetchMachine.transition('loading', {
type: 'TIMEOUT'
});
console.log(failureTimeoutState.meta);
// => {
// failure: {
// alert: 'Uh oh.'
// },
// 'failure.timeout': {
// message: 'The request timed out.'
// }
// }
TIP:聚合元数据
你如何处理元数据取决于你。理想情况下,元数据应仅包含 JSON 可序列化值。考虑以不同的方式合并/聚合元数据。例如,以下函数丢弃状态节点 ID 键(如果它们不相关)并合并元数据:
¥What you do with meta data is up to you. Ideally, meta data should contain JSON-serializable values only. Consider merging/aggregating the meta data differently. For example, the following function discards the state node ID keys (if they are irrelevant) and merges the meta data:
function mergeMeta(meta) {
return Object.keys(meta).reduce((acc, key) => {
const value = meta[key];
// Assuming each meta value is an object
Object.assign(acc, value);
return acc;
}, {});
}
const failureTimeoutState = fetchMachine.transition('loading', {
type: 'TIMEOUT'
});
console.log(mergeMeta(failureTimeoutState.meta));
// => {
// alert: 'Uh oh.',
// message: 'The request timed out.'
// }
# 注意
¥Notes
你永远不必手动创建
State
实例。将State
视为仅来自machine.transition(...)
或service.onTransition(...)
的只读对象。¥You should never have to create a
State
instance manually. TreatState
as a read-only object that only comes frommachine.transition(...)
orservice.onTransition(...)
.state.history
不会保留其历史记录以防止内存泄漏。state.history.history === undefined
。否则,你最终会创建一个巨大的链表并重新发明区块链,这是我们不关心的。¥
state.history
will not retain its history in order to prevent memory leaks.state.history.history === undefined
. Otherwise, you end up creating a huge linked list and reinventing blockchain, which we don't care to do.此行为可能会在未来版本中进行配置。
¥This behavior may be configurable in future versions.