如果输入在材料 ui 对话框中,react-hook-form 的 setValue 方法不起作用
Posted
技术标签:
【中文标题】如果输入在材料 ui 对话框中,react-hook-form 的 setValue 方法不起作用【英文标题】:react-hook-form's setValue method is not working if input is in material ui dialog 【发布时间】:2020-04-18 22:58:30 【问题描述】:我尝试使用 react-hook-form 来验证输入。但是我发现如果输入放在 Material UI 的对话框组件中,react-hook-form 的setValue
没有按预期工作,但是当我删除对话框组件时它可以工作。我猜原因是在组件挂载之前设置了值,但仍然找不到解决方案。
值会从服务器取回,所以不能使用react-hook-form的defaultValues
。
https://codesandbox.io/s/react-hook-form-material-ui-twbbw
我试过用useState
来控制输入值,但是还有一个问题。清除输入后,点击提交按钮,出现错误提示,我输入的第一个字母不会显示出来。
https://codesandbox.io/s/react-hook-form-material-ui-ve2en
【问题讨论】:
您可以简单地将其作为默认值添加到 Textfield 或使用 useForm(defaultValues: name: 123) 的表单 谢谢。似乎可行,但数据将从服务器获取,我不太确定在创建后更新defaultValues
是否是好方法。 codesandbox.io/s/react-hook-form-material-ui-viq6q
为什么不直接将默认值设置为文本字段。所以你不必更新钩子对象。这是因为 useEffect 在调用寄存器之前更新,并且在注册期间 Textfield 设置为“”(挂钩的默认值)。如果您在显示对话框后调用 setValue(异步,您已经在做),它可以工作。 setTimeout(() => (setValue("name", 123)), 1000);
您可以使用 useEffect 挂钩来设置来自服务器的值
【参考方案1】:
问题在于注册功能。在调用 Textfield 的 ref 之后,您正在使用 register 注册 Textfield。
在初始渲染后调用 useEffect 将名称设置为 123,并使用 setValue
。如果open
为真,则在useEffect 之后呈现对话框内容。
内容渲染完成后,调用带有寄存器的ref,将Textfield的默认值(这里undefined
)设置为name的值。
这就是为什么显示的 Textfield 的值是 ""。需要在调用 render 和 ref 回调后调用 setValue,使值保持不变。
您有两种选择:
-
在
open
更改后,使用异步延迟(setTimeout
或承诺)在 useEffect 中设置值 async。因此,如果您将 open
添加到 useEffect 依赖数组并将值设置为 async,它就可以工作。这是Sandbox。
设置文本字段的默认值或使用useForm(defaultValues: name: '123)
将默认值添加到挂钩。
【讨论】:
对话框组件会被复用,每次输入的默认值可能不同。如果我使用useForm(defaultValues: name: prop.value)
,默认值只是第一次设置,如果prop.value不同,我必须使用setValue
更新默认值。你提到的第一个选项适合我的情况,谢谢!!【参考方案2】:
对于外部受控组件
如果您使用的是 V3,我建议您使用 react-hook-form-input
https://github.com/react-hook-form/react-hook-form-input
import React from 'react';
import useForm from 'react-hook-form';
import RHFInput from 'react-hook-form-input';
import Select from 'react-select';
const options = [
value: 'chocolate', label: 'Chocolate' ,
value: 'strawberry', label: 'Strawberry' ,
];
function App()
const handleSubmit, register, setValue, reset = useForm();
return (
<form onSubmit=handleSubmit(data => console.log(data))>
<RHFInput
as=<Select options=options />
rules= required: true
name="reactSelect"
register=register
setValue=setValue
/>
<button type="button">Reset Form</button>
<button>submit</button>
</form>
);
如果您使用的是 V4,我建议您使用 Controller
https://react-hook-form.com/api/#Controller
import React from 'react';
import Select from 'react-select';
import TextField from "@material-ui/core";
import useForm, Controller from 'react-hook-form';
const options = [
value: 'chocolate', label: 'Chocolate' ,
value: 'strawberry', label: 'Strawberry' ,
value: 'vanilla', label: 'Vanilla' ,
];
function App()
const handleSubmit, control = useForm();
return (
<form onSubmit=handleSubmit(data => console.log(data))>
<Controller
as=<Select options=options />
control=control
rules= required: true
onChange=([selected]) =>
// React Select return object instead of value for selection
return value: selected ;
name="reactSelect"
/>
<Controller
as=<TextField />
name="firstName"
control=control
/>
<button>submit</button>
</form>
);
包装您的受控组件并在其中收集数据同时仍然隔离在外部受控组件内重新渲染的想法。
【讨论】:
感谢您的详细解释。我正在使用 V4,我曾尝试使用Controller
来包装受控组件。但是如果表单放在 Material UI 的 Dialog 组件中,setValue
仍然无法正常工作。 codesandbox.io/s/react-hook-form-material-ui-7hcne
@Sam 请提供更多关于仍然无法工作的详细信息
在示例中,我希望我使用setValue
来设置输入值“123”。但是我点击打开按钮,输入还是空的。问题应该是Dialog
组件引起的,如果我删除该组件,它会正常工作。
我认为问题在于何时调用 setValue,您可能应该在对话打开后调用它
谢谢,这是个不错的选择。在 Dialog onEnter
事件中调用 setValue
以确保组件已安装【参考方案3】:
由于setValue
有其特性,正如上面@Domino987 所解释的那样,对于那些用从服务器获取的数据填充表单的场景的替代方案是:
useState
保存获取的值;
Controller
s defaultValue
设置值和;
有条件渲染的表单。
一个伪例子:
const [state, setState] = useState(name: '', requested: false);
useEffect(() =>
HTTP_Service.getName().then(name =>
setCompanyInfo(name, requested: true)
);
, []);
const name, requested = state
return (requested ? <Text>Loading...</Text> : <View>
<Controller
as=
<Input
label=t('name')
placeholder=t('name')
/>
defaultValue=name
control=control
name="name"
onChange=args => args[0].nativeEvent.text
/>
</View>);
【讨论】:
【参考方案4】:react-hook-form 带有受控输入、是的验证、材质 UI 组件、setValue
import React from 'react';
import useForm, Controller from 'react-hook-form';
import yupResolver from '@hookform/resolvers/yup';
import Autocomplete from '@material-ui/lab/Autocomplete';
import TextField from '@material-ui/core';
import * as yup from 'yup';
const schema = yup.object().shape(
firstname: yup.string().required(),
buyer: yup.string().required(),
);
const UserForm = () =>
const
watch,
setValue,
register,
handleSubmit,
control,
formState: errors,
= useForm(
defaultValues:
item: "id":2,"name":"item2",
,
resolver: yupResolver(schema),
);
const itemList = [
id: 1, name: 'item1',
id: 2, name: 'item2',
];
return (
<div
style=
margin: '200px',
>
<form onSubmit=handleSubmit(d => console.table(d))>
<Controller
control=control
name="item"
rules=required: true
render=(field: onChange, value) => (
<Autocomplete
onChange=(event, item) =>
onChange(item);
value=value
options=itemList
getOptionLabel=item => (item.name ? item.name : '')
getOptionSelected=(option, value) =>
value === undefined || value === '' || option.id === value.id
renderInput=params => (
<TextField
...params
label="items"
margin="normal"
variant="outlined"
error=!!errors.item
helperText=errors.item && 'item required'
/>
)
/>
)
/>
<input type="submit" />
<button
onClick=() =>
setValue('item', id: 2, name: 'item2');
>
setValue
</button>
<h6>data from register</h6>
<pre>JSON.stringify(watch())</pre>
</form>
</div>
);
;
export default UserForm;
【讨论】:
以上是关于如果输入在材料 ui 对话框中,react-hook-form 的 setValue 方法不起作用的主要内容,如果未能解决你的问题,请参考以下文章
单击行材料-ui DataGrid内的按钮时如何设置行数据?