为什么这个赋值不触发?
Why this assign does not trigger?
看完official xstate tutorial, I tried to implement my own machine inspired by this post on dev.to by one of the xstate's dev.
除了output
似乎没有更新外,一切都按预期进行。我认为这项任务没有完成它的工作。我忘记了什么?
为了进行比较,这是来自 xstate 的工作 demo,其中上下文中的变量按预期更新。
分配的更多信息
我的代码:
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);
然后您需要 return 一个 Promise,并在 Promise 解决后让状态机更新上下文。
上下文在 invoke
的 onDone
属性 中更新。
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"
}
}
}
});
看完official xstate tutorial, I tried to implement my own machine inspired by this post on dev.to by one of the xstate's dev.
除了output
似乎没有更新外,一切都按预期进行。我认为这项任务没有完成它的工作。我忘记了什么?
为了进行比较,这是来自 xstate 的工作 demo,其中上下文中的变量按预期更新。
分配的更多信息我的代码:
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);
然后您需要 return 一个 Promise,并在 Promise 解决后让状态机更新上下文。
上下文在 invoke
的 onDone
属性 中更新。
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"
}
}
}
});