我有一个自定义文件上传字段,一旦您选择/删除文件,就会立即上传文件,并返回一个 UUID 以供以后提交。所以,当你删除一个文件时,基本上现在大多数 web 应用程序(例如 Facebook、Twitter 等)都会这样做。
使用 final-form 处理这一切都很容易 -onChange
一旦上传完成,我的字段只需调用 final-form 的函数以将 UUID 传递给 final-form。
但是,如果用户在上传仍在运行时提交表单,他们将提交没有文件 UUID 的表单,因为就最终表单而言,尚未选择任何文件。特别是对于较大的文件,这将是一个问题,因为用户可能没有意识到他们仍然需要等待(即使有加载指示器)。将字段标记为必填也不是一种选择,因为根本不提供文件是有效的(或者该字段可能允许多个文件,或者您正在替换以前上传的文件) - 所以该字段是“无效的”的唯一情况" 是当前正在上传文件的时间。
这是一个带有小型虚拟应用程序的代码框,应该为任何尝试解决它提供一个很好的起点:https ://codesandbox.io/s/poliished-fast-k80t7
这个想法是该字段在单击“假装开始上传”时变为无效,并在单击“假装完成上传”后再次有效。
请注意,我正在寻找一种干净的方法来做到这一点,同时保持事物分开,即我不想为此添加状态到包含Form
- 的组件中,也因为验证函数需要是幂等的,所以检查外部状态会有很多破损(正如我尝试做的那样)。
如果代码和框链接中断,这里是第一个链接的相关代码(因为另一个只是一个损坏的尝试):
import React, { useState } from "react";
import { render } from "react-dom";
import Styles from "./Styles";
import { Form, Field } from "react-final-form";
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const onSubmit = async values => {
await sleep(300);
window.alert(JSON.stringify(values, 0, 2));
};
const MyFileUploader = ({ input: { value, onChange }, meta: { invalid } }) => {
const [isUploading, setUploading] = useState(false);
const handleStartClick = () => {
setUploading(true);
};
const handleFinishClick = () => {
setUploading(false);
onChange("0xdeadbeef"); // let's pretend this is the file UUID ;)
};
const style = { color: invalid ? "#f00" : "#000" };
if (value) {
return <em style={style}>{value}</em>;
} else if (isUploading) {
return (
<button type="button" onClick={handleFinishClick} style={style}>
Pretend to finish uploading
</button>
);
} else {
return (
<button type="button" onClick={handleStartClick} style={style}>
Pretend to start uploading
</button>
);
}
};
const App = () => (
<Styles>
<h1>React Final Form</h1>
<Form
onSubmit={onSubmit}
initialValues={{ file: null }}
render={({ handleSubmit, form, submitting, values }) => (
<form onSubmit={handleSubmit}>
<div>
<label>File</label>
<Field name="file" component={MyFileUploader} />
</div>
<div className="buttons">
<button type="submit" disabled={submitting}>
Submit
</button>
<button type="button" onClick={form.reset} disabled={submitting}>
Reset
</button>
</div>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
</Styles>
);
render(<App />, document.getElementById("root"));