关于有限状态机的定义 和 已有的实现就不再赘述了
我们从一个现实的应用案例开始吧
前端的 UI 组件, 尤其是 面向 C 端的 App 或 小程序, 经常需要细致的体验优化
在许多异步和异常的情况给与特殊的提示和效果
比如淘宝的商品列表, 需要有 :
这四种状态, 就可以用有限状态机来描述
enum ComponentStatus {
normal,
loading,
error,
empty
}
我们常用的写法和伪代码 :
export default () => {
const [status, setStatus] = useState(ComponentStatus.loading)
useEffect(() => {
setStatus(loading)
fetch(xxx).then(resp => {
if(resp.data.length){
setStatus(normal)
}else {
setStatus(empty)
}
}).catch(e => {
setStatus(error)
})
}, [])
return (
<>
{status === ComponentStatus.normal && <NormalListUI />}
{status === ComponentStatus.loading && <LoadingUI />}
{status === ComponentStatus.error && <ErrorUI />}
{status === ComponentStatus.empty && <EmptyUI />}
</>
)
}
这种写法非常常见, 从枚举定义看来, 也比较清晰
不过我们还可以用更 JSX 的写法... 让他更加的语义化 ~
export default () => {
const [status, setStatus] = useState(ComponentStatus.loading)
useEffect(() => {
setStatus(loading)
fetch(xxx).then(resp => {
if(resp.data.length){
setStatus(normal)
}else {
setStatus(empty)
}
}).catch(e => {
setStatus(error)
})
}, [])
const Normal = StateMachine.create(ComponentStatus.normal)
const Loading = StateMachine.create(ComponentStatus.loading)
const Error = StateMachine.create(ComponentStatus.error)
const Empty = StateMachine.create(ComponentStatus.empty)
return (
<StateMachine current={status}>
<Normal>
<NormalList>
</Normal>
<Loading>
<LoadingUI>
</Loading>
<Error>
<ErrorUI />
</Error>
<Empty>
<EmptyUI />
</Empty>
</StateMachine>
)
}
emmmm ~ 更加 Semantic 了一些
这个小状态机的组件实现也非常简单 :
// StateMachine.tsx
import React from 'react'
const StateMachine = React.memo((props: { status: number; children: React.ReactElement[] }) => {
return (
<>
{React.Children.map(props.children, (c) =>
React.cloneElement(c as React.ReactElement, { status: props.status }),
)}
</>
)
})
const createState = (status: number) => {
return React.memo((props: { status?: number; children: React.ReactElement }) => {
return props.status === status ? props.children : null
})
}
export default Object.assign(StateMachine, { createState })
其它比如 Authorized 鉴权组件: 有权限和无权限状态, 对应显示和隐藏 children 组件, 也算是一个状态机的应用
它并不是一个功能完备的状态机, 而是用 JSX , 语义化的来描述一个状态机, 可读性较强 ~