You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React组件的useEffect中设置xstate状态机的状态

React XState 审批状态组件实现方案

功能实现说明

针对需求做了以下核心修改:

  • 组件挂载时通过useEffect拉取服务端存储的当前状态,同步到XState状态机
  • 封装状态切换逻辑,点击按钮先调用持久化接口,请求成功后再触发XState状态变更
  • 新增加载状态,避免接口请求过程中重复点击

完整实现代码

import React, { useEffect, useState } from 'react';
import { useParams, useHistory } from "react-router-dom";
import { createMachine, assign } from 'xstate';
import { useMachine } from "@xstate/react";
import {MagellanButton} from "./Styles";
import 'bootstrap/dist/css/bootstrap.min.css';
import '../App.css';

const approvalMachine = createMachine({
    id: 'approve',
    initial: 'loading', // 新增初始化加载状态
    context: {
        retries: 0,
        currentState: null
    },
    states: {
        loading: {
            on: {
                // 初始化同步状态事件
                INIT: {
                    target: (context, event) => event.initialState,
                    actions: assign({
                        currentState: (_, event) => event.initialState
                    })
                }
            }
        },
        'Not Submitted': {
            on: {
                SUBMIT: 'Pending Approval'
            }
        },
        'Pending Approval': {
            on: {
                CANCEL: 'Not Submitted',
                CHANGE: 'Change Request',
                DENIED: 'Denied',
                APPROVED: 'Approved'
            }
        },
        'Change Request': {
            on: {
                RESUBMITTED: 'Pending Approval',
                CANCEL: 'Not Submitted'
            }
        },
        Denied: {
            type: 'final'
        },
        Approved: {
            on: {
                PUBLISH: 'Published'
            }
        },
        Published: {
            type: "final"
        }
    }
});

function MagellanStateManager({id}) {
    const parameters = useParams();
    const history = useHistory()
    const [state, send] = useMachine(approvalMachine);
    const [isLoading, setIsLoading] = useState(false);

    // 组件初始化拉取服务端状态
    useEffect(() => {
        const fetchState = async () => {
            try {
                // 替换为实际的状态查询接口地址
                const res = await fetch(`/api/approval/${id}/state`);
                const data = await res.json();
                // 将服务端返回的状态同步到状态机
                send({
                    type: 'INIT',
                    initialState: data.state // 假设接口返回字段为state,值为状态机定义的状态名
                });
            } catch (err) {
                console.error('获取状态失败:', err);
                // 可根据需求添加错误提示、默认状态设置逻辑
                send({type: 'INIT', initialState: 'Not Submitted'});
            }
        };
        fetchState();
    }, [id, send]);

    // 封装状态切换持久化逻辑
    const handleStateChange = async (eventType) => {
        if (isLoading) return;
        setIsLoading(true);
        try {
            // 计算切换后的目标状态
            const targetState = approvalMachine.transition(state.value, eventType).value;
            // 替换为实际的状态持久化接口地址
            await fetch(`/api/approval/${id}/state`, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    state: targetState
                })
            });
            // 接口调用成功后触发状态机状态变更
            send(eventType);
        } catch (err) {
            console.error('状态更新失败:', err);
            // 可根据需求添加错误提示逻辑
        } finally {
            setIsLoading(false);
        }
    };

    return (
        <span style={{float: "right", marginTop: 8}}>
            <span className="m-form-label  ml-3">State:</span> <span>{state.value === 'loading' ? '加载中...' : state.value}</span>
            <MagellanButton className="ml-3" disabled={isLoading || !state.nextEvents.includes('SUBMIT')} onClick={() => handleStateChange('SUBMIT')}>Submit</MagellanButton>
            <MagellanButton className="ml-3" disabled={isLoading || !state.nextEvents.includes('CANCEL')} onClick={() => handleStateChange('CANCEL')}>Cancel</MagellanButton>
            <MagellanButton className="ml-3" disabled={isLoading || !state.nextEvents.includes('CHANGE')} onClick={() => handleStateChange('CHANGE')}>Change</MagellanButton>
            <MagellanButton className="ml-3" disabled={isLoading || !state.nextEvents.includes('RESUBMITTED')} onClick={() => handleStateChange('RESUBMITTED')}>Resubmit</MagellanButton>
            <MagellanButton className="ml-3" disabled={isLoading || !state.nextEvents.includes('DENIED')} onClick={() => handleStateChange('DENIED')}>Deny</MagellanButton>
            <MagellanButton className="ml-3" disabled={isLoading || !state.nextEvents.includes('APPROVED')} onClick={() => handleStateChange('APPROVED')}>Approve</MagellanButton>
            <MagellanButton className="ml-3" disabled={isLoading || !state.nextEvents.includes('PUBLISH')} onClick={() => handleStateChange('PUBLISH')}>Publish</MagellanButton>
        </span>
    )

}

export default MagellanStateManager;

关键改动说明

  • 新增了loading初始化状态,避免初始状态未加载完成时展示错误状态和允许误操作
  • 封装了handleStateChange统一处理按钮点击逻辑,先调用持久化接口,成功后再同步状态机状态,保证前后端状态一致
  • 添加了isLoading状态,防止接口请求过程中用户重复点击触发多次请求
  • 代码中接口地址为示例值,可根据实际业务替换为自身项目的接口地址,同时调整请求参数、返回值解析逻辑即可

内容的提问来源于stack exchange,提问作者Loren Cahlander

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 09:45:01