【问题标题】:Fields are not editable using React Hook Form使用 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: /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/})}
                        />
                        { 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.nameuser.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吗?
  • 我做了,但它不会观看或编辑phonerole(单选按钮)有什么想法吗?
  • 我尝试在 phonerole 上使用 watch 来控制台记录它们,但我无法更改或修改它们。
  • 更新:我尝试使用 defaultValue 而不是 value,因此它适用于姓名、电子邮件、电话,但现在我无法选择或修改单选按钮一的角色值。更新了上面的代码。

标签: node.js reactjs mongodb express react-redux


【解决方案1】:

不要在inputs 上使用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,因此它适用于姓名、电子邮件、电话,但现在我无法选择或修改单选按钮一的角色值。更新了上面的代码。
  • 不要在inputs 上使用valuedefaultValue 属性。看看 react form 钩子代码示例,它们可以向您展示做您需要的正确方法:github.com/react-hook-form/react-hook-form/tree/master/examples
【解决方案2】:

我认为您必须尝试使用​​onChange 或其他侦听器来输入并从侦听器回调中设置内部值。内在价值是你的状态。通常 React 用于受控输入,onChange 上的设置值会用新值重新渲染这个组件,并且可以编辑。试试;)

【讨论】:

  • React Hook Form 设计为与不受控制的输入字段一起使用作为默认值,因此这不是 OPs 问题的好答案。
  • 我同意。我尝试了他所说的,但根本没有用。谢谢马克。
猜你喜欢
  • 1970-01-01
  • 2022-11-02
  • 2021-01-20
  • 1970-01-01
  • 2022-12-15
  • 1970-01-01
  • 2021-05-25
  • 1970-01-01
  • 2022-07-30
相关资源
最近更新 更多