在试图笼统地讨论xState和状态机时,我想知道例如您如何向表单状态机提供API URL以使其可重用。我当前的解决方案是通过withContext提供它,但是感觉不对。
import { Machine, assign } from 'xstate';
const submitForm = async ({ formData, apiURL }) => {
const res = await fetch(apiURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
});
const message = await res.text();
return { status: res.status, message };
};
const formMachine = Machine({
id: 'form',
initial: 'idle',
context: {
formData: {},
apiURL: '',
},
states: {
idle: {
on: {
SEND: 'submitted',
INPUT: {
actions: assign({
formData: (ctx, { data }) => ({ ...ctx.formData, ...data }),
}),
},
},
},
submitted: {
id: 'form-submitted',
initial: 'pending',
states: {
pending: {
invoke: {
id: 'submitForm',
src: submitForm,
onDone: {
target: 'success',
actions: assign({
result: (ctx, event) => event.data,
}),
},
onError: {
target: 'failure',
actions: assign({
errorMessage: (ctx, event) => event.data,
}),
},
},
},
success: {},
failure: {
on: {
RETRY: 'pending',
SEND: 'pending',
},
},
},
},
},
});
export default formMachine;
import React from 'react';
import { useMachine } from '@xstate/react';
import formMachine from '../data/machines/form';
const ContactForm = () => {
const contactFormMachine = formMachine.withContext({
formData: {
name: '',
email: '',
message: '',
},
apiURL: '/api/contact',
});
const [current, send] = useMachine(contactFormMachine);
return (
<>
{
current.matches('submitted.success') ? (
<div>Message succesfully sent</div>
) : (
<form onSubmit={
(e) => {
e.preventDefault();
send('SEND');
}
}>
...
</form>
)
}
</>
);
};
export default ContactForm;
答案 0 :(得分:0)
我认为您有一个很好的解决方案,可以使该计算机按原样重用。这是xstate可视化工具存储库中的an example,可以使您对解决方案更满意:
const invokeSaveGist = (ctx: AppMachineContext, e: EventObject) => {
return fetch(`https://api.github.com/gists/` + ctx.gist!.id, {
method: 'post',
body: JSON.stringify({
description: 'Generated by XState Viz: https://xstate.js.org/viz',
public: true,
files: {
'machine.js': { content: e.code }
}
}),
headers: {
Authorization: `token ${ctx.token}`
}
}).then(async response => {
if (!response.ok) {
throw new Error((await response.json()).message);
}
return response.json();
});
};
如您所见,URL的“动态”部分也是从机器上下文派生的,当然,这是此处的要点ID,但也可以是URL的其他任何部分。
您可以考虑的另一种解决方案,尽管无论如何我都不会认为它是“更好”的解决方案(可能少了三行代码),但是当提交表单时,将apiUrl
作为数据传递给send('SEND');
。所以代替:
<form onSubmit={
(e) => {
e.preventDefault();
send('SEND');
}
}>
您可以尝试:
<form onSubmit={
(e) => {
e.preventDefault();
send('SEND', { apiUrl: 'api/contact'});
}
}>