TL;DR
这工作:https://codesandbox.io/s/stoic-beaver-ucydi
使用refactor表单重构后,此操作不起作用:https://codesandbox.io/s/objective-cloud-bkunr?file=/src/ControlledTextField.tsx
长话短说
没有反应钩形式(工作确定)
最近,我使用Fluent UI和自定义组件中的包装字段构建了一个有状态的React表单。
我包含了一个特性,在输入Site字段时生成Site字段中的值(在我的示例中,它只是复制字段值并删除URL无效的字符)。
(简化的)代码运行良好,如下所示:
import * as React from 'react';
import {useState} from 'react';
import { PrimaryButton } from 'office-ui-fabric-react';
import SiteTitleField from '../../../common/formFields/SiteTitleField';
import SiteUrlField from '../../../common/formFields/SiteUrlField';
export default function MyForm(props) {
const urlPrefix: string = "https://" + window.location.hostname + "/sites/";
const [siteTitle, setSiteTitle] = useState();
const [titleErrorMessage, setTitleErrorMessage] = useState('');
const [siteUrl, setsiteUrl] = useState();
const [urlErrorMessage, setUrlErrorMessage] = useState('');
function handleTitleChange(e) {
if (e.target.value.length) {
setTitleErrorMessage('');
} else {
setTitleErrorMessage('This field is required.');
}
setSiteTitle(e.target.value);
setsiteUrl(e.target.value.replace(/[^A-Za-z0-9_-]/g, ""));
}
function handleUrlChange(e) {
if (e.target.value.length) {
setUrlErrorMessage('');
} else {
setUrlErrorMessage('This field is required.');
}
setsiteUrl(e.target.value);
}
function handleButtonClick(e) {
// call to API
}
return (
<SiteTitleField
siteTitle={siteTitle}
titleErrorMessage={titleErrorMessage}
handleTitleChange={handleTitleChange}
/>
<SiteUrlField
siteUrl={siteUrl}
urlErrorMessage={urlErrorMessage}
urlPrefix={urlPrefix}
handleUrlChange={handleUrlChange}
/>
<PrimaryButton
text="Create a Request"
onClick={handleButtonClick}
/>
);
}
SiteTitleField组件:
import * as React from 'react';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
export default function SiteTitleField(props) {
return (
<TextField
value={props.siteTitle}
required
aria-required="true"
errorMessage={props.titleErrorMessage}
label="Site Title"
placeholder="Set the title of the site"
onChange={props.handleTitleChange}
/>
);
}
SiteUrlField组件:
import * as React from 'react';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
export default function SiteUrlField(props) {
return (
<TextField
value={props.siteUrl}
required
aria-required="true"
errorMessage={props.urlErrorMessage}
label="Site URL"
prefix={props.urlPrefix}
placeholder="Set site URL alias"
onChange={props.handleUrlChange}
/>
);
}
使用React形式(工作不正常)
现在,我正在尝试使用refactor表单和Yup验证模式重构我的表单。
我使用组件及其呈现属性包装了Fluent UI TextField组件:
import * as React from 'react';
import { Control, Controller, FieldErrors } from "react-hook-form";
import { TextField } from 'office-ui-fabric-react';
export interface IControlledTextFieldProps {
control: Control<any>;
name: string;
errors: FieldErrors<any>;
label?: string;
prefix?: string;
placeholder?: string;
onChangeCallback?: (...event: any[]) => void;
refValue?: string;
}
export const ControlledTextField: React.FC<IControlledTextFieldProps> = ({
control,
name,
errors,
label,
prefix,
placeholder,
onChangeCallback,
refValue,
}) => {
return (
<Controller
name={name}
control={control}
disabled={disabled}
render={({ onChange, onBlur, value, name: fieldName }) => (
<TextField
onChange={(event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {onChange(refValue); onChangeCallback && onChangeCallback(event);}}
value={refValue}
onBlur={onBlur}
name={fieldName}
errorMessage={errors[fieldName] && errors[fieldName].message}
label={label}
prefix={prefix}
placeholder={placeholder}
/>
)}
/>
);
};
我相应地替换了SiteTitleField和SiteUrlField的代码,并添加了一个简单的Yup验证模式:
const schema = yup.object().shape({
siteTitle: yup.string().required("Site Title needs to be provided."),
siteUrl: yup.string().required("Site URL needs to be provided."),
});
const { handleSubmit, errors, control } = useForm<Inputs>({
resolver: yupResolver(schema)
});
我用<form>
标记包装了表单,并相应地更改了字段属性:
<form onSubmit={handleSubmit(handleButtonClick)}>
<SiteTitleField
name="siteTitle"
control={control}
errors={errors}
handleTitleChange={handleTitleChange}
/>
<SiteUrlField
name="siteUrl"
control={control}
errors={errors}
siteUrl={siteUrl}
urlPrefix={urlPrefix}
/>
<PrimaryButton
text="Create a Request"
type="submit"
/>
</form>
关于状态,我只留下了值复制所需的东西:
const [siteUrl, setsiteUrl] = useState();
function handleTitleChange(e) {
setsiteUrl(e.target.value.replace(/[^A-Za-z0-9_-]/g, ""));
}
问题
我不能让React表单验证和我的值复制功能同时工作。
如果使用以下代码,验证效果很好,但用户无法编辑站点URL字段:
onChange={(event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {onChange(refValue); onChangeCallback && onChangeCallback(event);}}
value={refValue}
或者复制和编辑字段值很好,但是即使输入了值,验证也表明这两个字段都是空的(必需),当使用以下代码时:
onChange={onChangeCallback}
value={refValue}
发布于 2020-12-01 19:36:12
好吧,我想出来了。
而不是使用状态更新字段值。
const [siteUrl, setsiteUrl] = useState();
function handleTitleChange(e) {
setsiteUrl(e.target.value.replace(/[^A-Za-z0-9_-]/g, ""));
}
我应该使用useForm
的setValue
const {
handleSubmit,
errors,
control,
setValue // added
} =
useForm<Inputs>({
resolver: yupResolver(schema)
});
function handleTitleChange(e) {
// changed:
setValue("siteUrl", e.target.value.replace(/[^A-Za-z0-9_-]/g, ""), {
shouldValidate: true
});
}
而value
in ControlledTextField
应该简单地解析为:
value={value}
工作解决方案:https://codesandbox.io/s/focused-montalcini-ehbp3?file=/src/App.tsx
https://stackoverflow.com/questions/65100499
复制