有没有办法在 useEffect 的反应组件中设置 xstate 机器的状态?

Posted

技术标签:

【中文标题】有没有办法在 useEffect 的反应组件中设置 xstate 机器的状态?【英文标题】:Is there a way to set the state of an xstate machine in a react component in useEffect? 【发布时间】:2022-01-09 02:44:25 【问题描述】:

我有以下 React.js 组件需要以下内容:

通过使用 fetch 调用服务器端 API 来保持单击按钮时的状态。 当组件初始化时,在调用useEffect 之后在组件中设置状态,该useEffect 使用fetch 调用服务器端API 以获取对象的当前状态。

这里是组件的显示



这是我目前所拥有的。

import React,  useEffect, useState  from 'react';
import  useParams, useHistory  from "react-router-dom";
import  createMachine  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: 'Not Submitted',
    context: 
        retries: 0
    ,
    states: 
        '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);

    useEffect(() => 
    , []);

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



export default MagellanStateManager;

【问题讨论】:

只要 API 响应是 xstate 的有效 JSON,the docs show the way to do it 【参考方案1】:

从 Taxel 的评论中,我找到了解决方案。这是更改后的反应元素。我将不胜感激任何额外的 cmets 以使其变得更好。

谢谢!

import React, useEffect, useState from 'react';
import  createMachine, interpret  from 'xstate';
import MagellanButton from "./Styles";
import 'bootstrap/dist/css/bootstrap.min.css';
import '../App.css';

const approvalMachine = createMachine(
    id: 'approve',
    initial: 'Not Submitted',
    context: 
        retries: 0
    ,
    states: 
        '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 [service, setService] = useState(interpret(approvalMachine));
    const [counter, setCounter] = useState(0);

    useEffect(() => 
        // TODO: Add the fetch to get the stored state from the server
        const approvalService = interpret(approvalMachine);
        approvalService.start(approvalMachine.initialState);
        setService(approvalService);
        // TODO: Add dependencies for the useEffect for when identification values change
    , []);

    function storeState(theEvent) 
        const newState = service.send(theEvent);
        const theState = JSON.stringify(newState);
        // TODO: Add the fetch to send the state to the server to be stored
        console.log(theState);
        setCounter(counter + 1);
    

    function notEvent(theEvent) 
        if (service != null && service._state != null) 
            return !service._state.nextEvents.includes(theEvent);
         else 
            return true;
        
    

    return (
        <span style=float: "right", marginTop: 8>
            <span className="m-form-label  ml-3">State:</span> <span>service ? service._state ? service._state.value : "" : ""</span>
            <MagellanButton className="ml-3" disabled=notEvent('SUBMIT') onClick=() => storeState('SUBMIT')>Submit</MagellanButton>
            <MagellanButton className="ml-3" disabled=notEvent('CANCEL') onClick=() => storeState('CANCEL')>Cancel</MagellanButton>
            <MagellanButton className="ml-3" disabled=notEvent('CHANGE') onClick=() => storeState('CHANGE')>Change</MagellanButton>
            <MagellanButton className="ml-3" disabled=notEvent('RESUBMITTED') onClick=() => storeState('RESUBMITTED')>Resubmit</MagellanButton>
            <MagellanButton className="ml-3" disabled=notEvent('DENIED') onClick=() => storeState('DENIED')>Deny</MagellanButton>
            <MagellanButton className="ml-3" disabled=notEvent('APPROVED') onClick=() => storeState('APPROVED')>Approve</MagellanButton>
            <MagellanButton className="ml-3" disabled=notEvent('PUBLISH') onClick=() => storeState('PUBLISH')>Publish</MagellanButton>
        </span>
    )



export default MagellanStateManager;

【讨论】:

我已经构建了一个 React 样板和 XState,也许它对你有用 gitlab.com/disruptivo.io/internals/frontend/react-starter-kit 另外我在 Medium 上写了一篇关于它的简短帖子 medium.com/@luisbar180492/…

以上是关于有没有办法在 useEffect 的反应组件中设置 xstate 机器的状态?的主要内容,如果未能解决你的问题,请参考以下文章

React - useEffect axios请求中设置的状态为空

你如何在反应中设置一个组件与不同组件的状态?

如何在反应中设置视频端组件的状态?

React中useEffect使用

React Hooks:如何在 useEffect 中设置状态?

有没有办法在 Vue DatePicker 中设置选定的选项?