为啥这个分配不触发?

Posted

技术标签:

【中文标题】为啥这个分配不触发?【英文标题】:Why this assign does not trigger?为什么这个分配不触发? 【发布时间】:2021-11-12 11:29:19 【问题描述】:

在阅读了official xstate tutorial 之后,我尝试在dev.to by one of the xstate's dev 上的这篇文章的启发下实现我自己的机器。

除了output 似乎没有更新之外,一切都按预期工作。我认为这项任务没有完成它的工作。我忘记了什么?

为了比较,这里有一个来自 xstate 的工作 demo,其中上下文中的变量按预期更新。

在Context | XState Docs上分配的更多信息

我的代码:

import "./styles.css";
import * as React from "react";
import * as ReactDOM from "react-dom";
import  createMachine, assign  from "xstate";
import  useMachine  from "@xstate/react";

interface FetchContext 
  output: string;


const fetchifetch = async () => 
  return await fetch(
    "https://jsonplaceholder.typicode.com/todos/1"
  ).then((response) => response.json());
;

const fetchMachine = createMachine<FetchContext>(
  initial: "idle",
  context: 
    output: "wesh" // none selected
  ,
  states: 
    idle: 
      on: 
        FETCH: "loading"
      
    ,
    loading: 
      invoke: 
        src: (context, event) => async (send) => 
          setTimeout(async () => 
            const data = await fetchifetch();
            console.log("done");
            console.log(data);
            // well. here I want to assign something to output
            assign(
              output: (context, event) => data.title
            );
            send("FETCHED_SUCCESSFULLY");
          , 4000);
          console.log("start");
        ,
        onError: 
          target: "idle"
        
      ,
      on: 
        FETCHED_SUCCESSFULLY: 
          target: "idle"
        
      
    ,
    fetch: 
      on: 
        CLOSE: "idle"
      
    
  
);

function App() 
  const [current, send] = useMachine(fetchMachine);
  const  output  = current.context;

  return (
    <div className="App">
      <h1>XState React Template</h1>
      <br />
      <input
        disabled=current.matches("loading")
        defaultValue="yo"
        onChange=(e) => console.log(e.currentTarget.value)
      />
      <button
        disabled=current.matches("loading")
        onClick=() => send("FETCH")
      >
        click to fetch
      </button>

      <!-- let's display the result over here -->
      <div>output</div>
      <div>current.context.output</div>
    </div>
  );


const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

【问题讨论】:

【参考方案1】:

然后您需要返回一个 Promise,并在 Promise 解决后让状态机更新上下文。

上下文在invokeonDone 属性中更新。

const fetchMachine = createMachine<FetchContext>(
  initial: "idle",
  context: 
    output: "wesh" // none selected
  ,
  states: 
    idle: 
      on: 
        FETCH: "loading"
      
    ,
    loading: 
      invoke: 
        src: (context, event) => async (send) => 
          return new Promise((resolve, reject) => 
            setTimeout(async () => 
              try 
                const data = await fetchifetch();
                resolve(data.title);
               catch (err) 
                 reject(err);
              
            , 4000);
          );
        ,
        onDone: 
          target: "fetch",
          actions: assign(
            output: (_, event) => event.data,
          )
        ,
        onError: 
          target: "idle"
        
      ,
      on: 
        FETCHED_SUCCESSFULLY: 
          target: "idle",
        
      
    ,
    fetch: 
      on: 
        CLOSE: "idle"
      
    
  
);

【讨论】:

我们可以写invoke: src: fetchifetch, onDone: target: "fetch", actions: assign( output: (_, event) =&gt; event.data.title ), onError: target: "idle" 是的,我推测超时的原因是为了模拟长时间的延迟 是的,我为此添加了 :)

以上是关于为啥这个分配不触发?的主要内容,如果未能解决你的问题,请参考以下文章

为啥顺序在这个链式分配中很重要?

为啥我分配对象本身不能正常工作?

为啥这个 (null || !TryParse) 条件会导致“使用未分配的局部变量”?

为啥 std::optional 不允许“移动构造和仅复制分配”类型的移动分配?

为啥我不能动态分配这个结构字符串的内存?

为啥 Java 使用堆来分配内存? [复制]