【问题标题】: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);

【问题讨论】:

    标签: javascript reactjs typescript xstate


    【解决方案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" }}
    • 是的,我推测超时的原因是为了模拟长时间的延迟
    • 是的,我为此添加了 :)
    猜你喜欢
    • 1970-01-01
    • 2018-06-15
    • 1970-01-01
    • 2012-02-17
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多