使用 React Hook Form 无法编辑字段
Posted
技术标签:
【中文标题】使用 React Hook Form 无法编辑字段【英文标题】:Fields are not editable using React Hook Form 【发布时间】:2021-04-09 13:31:19 【问题描述】:我有这个 UserEditScreen.js
文件,我通过 React-Redux 从 mongodb 提取所有数据。
我需要进行一些验证,所以我使用了React Hook Form 来执行此操作。所以在我的代码上:
import React, useState, useEffect from 'react'
import useForm from 'react-hook-form'
import useDispatch, useSelector from 'react-redux'
import Message from '../components/Message'
import Loader from '../components/Loader'
import getUserDetails, updateUser from '../actions/userActions'
import USER_UPDATE_RESET from '../constants/userConstants'
const UserEditScreen = ( match, history ) =>
const watch, register, errors, handleSubmit = useForm()
console.log('role')
const userId = match.params.id
// const [name, setName] = useState('')
// const [email, setEmail] = useState('')
// const [phone, setPhone] = useState('')
// const [role, setRole] = useState('')
const dispatch = useDispatch()
const userDetails = useSelector(state => state.userDetails)
const loading, error, user = userDetails
const userUpdate = useSelector(state => state.userUpdate)
const loading:loadingUpdate, error:errorUpdate, success:successUpdate = userUpdate
useEffect(() =>
if(successUpdate)
dispatch( type: USER_UPDATE_RESET )
history.push('/admin/userslist')
else
if(!user.name || user._id !== userId)
dispatch(getUserDetails(userId))
// else
// setName(user.name)
// setEmail(user.email)
// setPhone(user.phone)
// setRole(user.role)
//
, [dispatch, history, userId, user, successUpdate])
const submitHandler = (data, e) =>
e.preventDefault()
const name, email, phone, role = data
dispatch(updateUser( _id: userId, name, email, phone, role ))
return (
<>
<h1>Edit User</h1>
loadingUpdate && <Loader />
errorUpdate && <Message variant='danger'>errorUpdate</Message>
loading ? <Loader /> : error ? <Message variant='danger'>error</Message> : (
<form onSubmit=submitHandler>
<div className="form-group">
<label for="name">Name</label>
<input
type="text"
name="name"
value=user.name
className=`form-control $errors.name ? 'is-invalid' : ''`
id="name"
ref=register( required: true, minLength: 2, maxLength: 30 )
/>
errors.name && errors.name.type ==='required' && <p className="text-danger">Name is required.</p>
errors.name && errors.name.type ==='minLength' && <p className="text-danger">Name is too short.</p>
errors.name && errors.name.type ==='maxLength' && <p className="text-danger">Name is exceeds maximum length.</p>
</div>
<div className="form-group">
<label for="email">Email address</label>
<input
type="email"
name="email"
value=user.email
className=`form-control $errors.email ? 'is-invalid' : ''`
id="email"
ref=register( required: true, minLength: 8, maxLength: 30, pattern: /^\S+@\S+\.\S+$/ )
/>
errors.email && errors.email.type ==='required' && <p className="text-danger">Email is required.</p>
errors.email && errors.email.type ==='minLength' && <p className="text-danger">Email length is too small.</p>
errors.email && errors.email.type ==='maxLength' && <p className="text-danger">Email exceeds maximum length.</p>
errors.email && errors.email.type ==='pattern' && <p className="text-danger">That is not a valid email.</p>
</div>
<div className="form-group">
<label for="phone">Phone</label>
<input
type="text"
value=user.phone
className=`form-control $errors.phone ? 'is-invalid' : ''`
id="phone"
ref=register( required: true, minLength: 10, maxLength: 13, pattern: /^(\+\d1,2\s)?\(?\d3\)?[\s.-]\d3[\s.-]\d4$/)
/>
errors.phone && errors.phone.type ==='required' && <p className="text-danger">Phone is required.</p>
errors.phone && errors.phone.type ==='minLength' && <p className="text-danger">Phone length is too small.</p>
errors.phone && errors.phone.type ==='maxLength' && <p className="text-danger">Phone exceeds maximum length.</p>
errors.phone && errors.phone.type ==='pattern' && <p className="text-danger">Phone is not a valid phone.</p>
</div>
<div className="form-group">
<label for="phone">User Role</label>
<div class="role">
<input
type="radio"
className="btn-check"
name="role"
id="administrator"
autocomplete="off"
value='administrator'
ref=register( required: true )
checked=user.role === 'administrator'
/>
<label className="btn btn-outline-success" for="administrator">Administrator</label>
<input
type="radio"
className="btn-check"
name="role"
id="resort-owner"
autocomplete="off"
value='resortOwner'
ref=register( required: true )
checked=user.role === 'resortOwner'
/>
<label className="btn btn-outline-success" for="resort-owner">Resort Owner</label>
<input
type="radio"
className="btn-check"
name="role"
id="reviewer"
autocomplete="off"
value='reviewer'
ref=register( required: true )
checked=user.role === 'reviewer'
/>
<label className="btn btn-outline-success" for="reviewer">Reviewer</label>
errors.role && errors.role.type ==='required' && <p className="text-danger">Choose a role.</p>
</div>
</div>
<button type="submit" className="btn btn-primary">Update</button>
</form>
)
</>
)
export default UserEditScreen
如您所见,我注释掉了useState
字段并尝试通过user.name
、user.email
等直接从userDetails
操作中提取数据。我通过每个输入字段值属性设置了这些数据。
但是,执行此操作后,我无法再修改或编辑任何字段。我需要设置一些验证,但希望仍然能够编辑每个字段并使用 react hook 表单提交表单,但我不知道如何解决这个问题。
知道如何解决这个问题并使表单字段可编辑以及能够使用反应钩子表单提交带有验证的表单吗?请帮忙。
更新:我尝试使用defaultValue
而不是value
,因此它适用于姓名、电子邮件、电话,但现在我无法选择或修改单选按钮role
的值一。这是我更新的代码。
const UserEditScreen = ( match, history ) =>
const watch, register, errors, handleSubmit = useForm()
console.log(watch('name'))
console.log(watch('email'))
console.log(watch('phone'))
console.log(watch('role'))
const userId = match.params.id
// const [name, setName] = useState('')
// const [email, setEmail] = useState('')
// const [phone, setPhone] = useState('')
// const [role, setRole] = useState('')
const dispatch = useDispatch()
const userDetails = useSelector(state => state.userDetails)
const loading, error, user = userDetails
const userUpdate = useSelector(state => state.userUpdate)
const loading:loadingUpdate, error:errorUpdate, success:successUpdate = userUpdate
useEffect(() =>
if(successUpdate)
dispatch( type: USER_UPDATE_RESET )
history.push('/admin/userslist')
else
if(!user.name || user._id !== userId)
dispatch(getUserDetails(userId))
// else
// setName(user.name)
// setEmail(user.email)
// setPhone(user.phone)
// setRole(user.role)
//
, [dispatch, history, userId, user, successUpdate,])
const submitHandler = (data, e) =>
e.preventDefault()
const name, email, phone, role = data
dispatch(updateUser( _id: userId, name, email, phone, role ))
return (
<>
<h1>Edit User</h1>
loadingUpdate && <Loader />
errorUpdate && <Message variant='danger'>errorUpdate</Message>
loading ? <Loader /> : error ? <Message variant='danger'>error</Message> : (
<form onSubmit=handleSubmit(submitHandler)>
<div className="form-group">
<label for="name">Name</label>
<input
type="text"
name="name"
defaultValue=user.name
className=`form-control $errors.name ? 'is-invalid' : ''`
id="name"
ref=register( required: true, minLength: 2, maxLength: 30 )
/>
errors.name && errors.name.type ==='required' && <p className="text-danger">Name is required.</p>
errors.name && errors.name.type ==='minLength' && <p className="text-danger">Name is too short.</p>
errors.name && errors.name.type ==='maxLength' && <p className="text-danger">Name is exceeds maximum length.</p>
</div>
<div className="form-group">
<label for="email">Email address</label>
<input
type="email"
name="email"
defaultValue=user.email
className=`form-control $errors.email ? 'is-invalid' : ''`
id="email"
ref=register( required: true, minLength: 8, maxLength: 30, pattern: /^\S+@\S+\.\S+$/ )
/>
errors.email && errors.email.type ==='required' && <p className="text-danger">Email is required.</p>
errors.email && errors.email.type ==='minLength' && <p className="text-danger">Email length is too small.</p>
errors.email && errors.email.type ==='maxLength' && <p className="text-danger">Email exceeds maximum length.</p>
errors.email && errors.email.type ==='pattern' && <p className="text-danger">That is not a valid email.</p>
</div>
<div className="form-group">
<label for="phone">Phone</label>
<input
type="text"
name="phone"
defaultValue=user.phone
className=`form-control $errors.phone ? 'is-invalid' : ''`
id="phone"
ref=register( required: true, minLength: 10, maxLength: 13 )
/>
errors.phone && errors.phone.type ==='required' && <p className="text-danger">Phone is required.</p>
errors.phone && errors.phone.type ==='minLength' && <p className="text-danger">Phone length is too small.</p>
errors.phone && errors.phone.type ==='maxLength' && <p className="text-danger">Phone exceeds maximum length.</p>
errors.phone && errors.phone.type ==='pattern' && <p className="text-danger">Phone is not a valid phone.</p>
</div>
<div className="form-group">
<label for="phone">User Role</label>
<div class="role">
<input
type="radio"
className="btn-check"
name="role"
id="administrator"
autocomplete="off"
value='administrator'
ref=register( required: true )
checked=user.role === 'administrator'
/>
<label className="btn btn-outline-success" for="administrator">Administrator</label>
<input
type="radio"
className="btn-check"
name="role"
id="resort-owner"
autocomplete="off"
value='resortOwner'
ref=register( required: true )
checked=user.role === 'resortOwner'
/>
<label className="btn btn-outline-success" for="resort-owner">Resort Owner</label>
<input
type="radio"
className="btn-check"
name="role"
id="reviewer"
autocomplete="off"
value='reviewer'
ref=register( required: true )
checked=user.role === 'reviewer'
/>
<label className="btn btn-outline-success" for="reviewer">Reviewer</label>
errors.role && errors.role.type ==='required' && <p className="text-danger">Choose a role.</p>
</div>
</div>
<button type="submit" className="btn btn-primary">Update</button>
</form>
)
</>
)
【问题讨论】:
你试过用defaultValue
代替value
吗?
我做了,但它不会观看或编辑phone
或role
(单选按钮)有什么想法吗?
我尝试在 phone
和 role
上使用 watch
来控制台记录它们,但我无法更改或修改它们。
更新:我尝试使用 defaultValue 而不是 value,因此它适用于姓名、电子邮件、电话,但现在我无法选择或修改单选按钮一的角色值。更新了上面的代码。
【参考方案1】:
不要在input
s 上使用value
属性。如果你也没有为 onChange
提供值,React 将使表单控件无法编辑。改为使用reset
钩子方法异步设置字段值:
const watch, register, errors, handleSubmit, reset = useForm();
...
useEffect(() =>
reset(
name: user.name,
email: user.email,
...
);
, [reset, user]);
阅读React docs on controlled form components
见example on codesandbox.io
【讨论】:
不确定,但它没有拿起电话和角色。我在上面更新了我的问题。此外,我正在通过 redux FYI 获取数据库上的一些数据,而不仅仅是一个常规的创建表单,它是一个编辑表单 更新:我尝试使用 defaultValue 而不是 value,因此它适用于姓名、电子邮件、电话,但现在我无法选择或修改单选按钮一的角色值。更新了上面的代码。 不要在input
s 上使用value
或defaultValue
属性。看看 react form 钩子代码示例,它们可以向您展示做您需要的正确方法:github.com/react-hook-form/react-hook-form/tree/master/examples【参考方案2】:
我认为您必须尝试使用onChange
或其他侦听器来输入并从侦听器回调中设置内部值。内在价值是你的状态。通常 React 用于受控输入,onChange
上的设置值会用新值重新渲染这个组件,并且可以编辑。试试;)
【讨论】:
React Hook Form 设计为与不受控制的输入字段一起使用作为默认值,因此这不是 OPs 问题的好答案。 我同意。我尝试了他所说的,但根本没有用。谢谢马克。以上是关于使用 React Hook Form 无法编辑字段的主要内容,如果未能解决你的问题,请参考以下文章
如何使 react-hook-form 在一页中使用多个表单?
文本字段更改的值未在 OnSubmit 中更新 - React-Hook-Form 和 React Js
react-hook-form 的 DefaultValues 未将值设置为 React JS 中的输入字段
react-hook-form 在组件中使用以传递动态文本字段的道具
在 react-hook-form 的 useFieldArray 上异步调用 reset 时,reset 无法正常工作