1

在阅读了官方的 xstate 教程之后,我尝试实现我自己的机器,灵感来自xstate 的 dev.to上的这篇文章。

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

编辑wandering-violet-obe1q

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

有关分配上下文的更多信息 | XState 文档

我的代码:

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);
4

1 回答 1

1

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

上下文在 的onDone属性中更新invoke

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"
      }
    }
  }
});
于 2021-09-17T16:20:20.503 回答