在无状态组件中反应 material-ui 表单验证。反应钩形式不起作用

时间:2020-12-21 16:59:43

标签: javascript reactjs react-hook-form

我正在尝试对 material-ui TextField 输入实现一些非常基本的错误处理。 我希望表单输入仅在单击时显示错误(如果它不符合要求),但在我输入时动态更新错误状态,以便输入我的方式错误状态消除了错误消息。

子表单是无状态的,因为 props 是从父表单传递过来的,并且由父表单的更改处理程序更新。

App.js

import React, {Component} from 'react'
import PersonalDetails from "./components/PersonalDetails"
import EducationDetails from "./components/EducationDetails"
import ExperienceDetails from "./components/ExperienceDetails"
import Header from "./components/Header"
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom'

class App extends Component {
  constructor(props) {
    super(props)

    this.state = {
      name: "",
      email: "",
      phone: "",
      education: [{
        school: "",
        course: "",
        startDateEdu: "",
        endDateEdu: ""
      }],
      experience: [{
        company: "",
        role: "",
        startDateExp: "",
        endDateExp: "",
        details: ""
      }],
    }
  }

  // All changes across forms are handled here
  handleChange = (e) => {
    if(["name", "email", "phone"].includes(e.target.dataset.fieldType)) {
      this.setState({ [e.target.dataset.fieldType]: e.target.value }) 
    }
    else if(["school", "course", "startDateEdu", "endDateEdu"].includes(e.target.dataset.fieldType)) {
      let education = [...this.state.education]
      education[e.target.dataset.id][e.target.dataset.fieldType] = e.target.value
      this.setState({ education })
    }
    else if(["company", "role", "startDateExp", "endDateExp", "details"].includes(e.target.dataset.fieldType)) {
      let experience = [...this.state.experience]
      experience[e.target.dataset.id][e.target.dataset.fieldType] = e.target.value
      this.setState({ experience })
    }
     
  }

  addEducation = () => {
    const newEdu = { school: "", course: "", startDateEdu: "", endDateEdu: ""}
    this.setState({ education: [...this.state.education, newEdu] })       
  }

  addExperience = (e) => {
    const newExp = { company: "", role: "", startDateExp: "", endDateExp: "", details: ""}
    this.setState({ experience: [...this.state.experience, newExp] })       
  }

  render() {
    const {name, email, phone, education, experience} = this.state
    const values = {name, email, phone, education, experience}

    return (
      <Router>
          <Route
            path = "/" 
            component={Header}
          />

          <Switch>
            <Route
              path = "/personal" 
              render={(props) => (
                <PersonalDetails 
                  {...props} 
                  values={values}
                  handleChange={this.handleChange} 
                />
              )} 
            />

            <Route
              path = "/education" 
              render={(props) => (
                <EducationDetails 
                  {...props} 
                  values={values}
                  handleChange = {this.handleChange}
                  addEdu={this.addEducation}
                />
              )} 
            />

            <Route
              path = "/experience" 
              render={(props) => (
                <ExperienceDetails 
                  {...props} 
                  values={values}
                  handleChange = {this.handleChange}
                  addExp={this.addExperience}
                />
              )} 
            />
          </Switch>
      </Router>
    )
  }
}

我尝试使用 TextField 的内置 errorhelperText 道具,如下所示,但这会在表单加载后立即导致错误状态,因为这些字段一开始是空的。

PersonalDetails.js

import React, {useEffect} from 'react'
import { TextField } from '@material-ui/core'
import { Link } from 'react-router-dom'
import { useForm, Controller } from "react-hook-form";
import NameForm from "./NameForm";

const PersonalDetails = ({values, handleChange}) => {
    return (
        <div>
            <h1>Personal Details</h1>
            <form autoComplete="off">
                <TextField 
                    type="text"
                    label="Name" 
                    value={values.name} 
                    onChange={handleChange}
                    inputProps={{ "data-field-type": "name" }}
                    error={values.name === "" ? true : false}
                    helperText={values.name === "" ? "Required" : ""}
                />
                <br />
                <br />
            </form>
            <Link to="/education"><button>Next Page</button></Link>
        </div>
    )
  } 

export default PersonalDetails

然后我发现了 react-hook-form,它更接近我想要完成的事情,因为输入仅在 onBlur 事件上验证,但这意味着在我输入时不会纠正现有错误,直到点击离开输入,如下所示。

PersonalDetails.js(再次)

import React, {useEffect} from 'react'
import { TextField } from '@material-ui/core'
import { Link } from 'react-router-dom'
import { useForm, Controller } from "react-hook-form";
import NameForm from "./NameForm";


const PersonalDetails = ({values, handleChange}) => {
    const { register, errors, trigger } = useForm({
        // Changing mode to 'onChange' causes strange behaviour
        mode: 'onBlur',
        reValidateMode: 'onChange',
    });

    return (
        <div>
            <h1>Personal Details</h1>
            <form autoComplete="off">
                <TextField 
                    type="text"
                    label="Name" 
                    name="name"
                    value={values.name} 
                    onChange={handleChange}
                    inputProps={{ "data-field-type": "name" }}
                    inputRef={register({required: true, minLength: 3})}
                    error={errors.name ? true : false}
                    helperText={errors.name ? "Required" : ""}
                />
                <br />
                <br />
            </form>
            <Link to="/education"><button>Next Page</button</Link>
        </div>
    )
} 

export default PersonalDetails

这是我感到困惑的地方。如果我将 useForm 的 mode 属性从 mode: onBlur 更改为 mode: onChange,组件似乎会在需要更新错误状态时跳过 onChange 处理程序。这会导致错过更新事件,从而导致输入中断(键入“Hello”会产生“elo”)

我似乎错误地使用了 react-hook-form,因为大多数文档都涉及有状态的表单组件,但我还能如何解决这个问题。我只是在学习 React,似乎如果你想跨多个页面/路由维护表单的完整状态,你应该在父级中维护状态,并将状态和处理程序作为道具从父级传递给子级,但我检查过的几乎所有表单验证库都没有这样做。

我可以使用一些建议/指导。对于任何错误/误解,我深表歉意,因为我对 React.js 非常陌生,才刚刚开始使用它。

谢谢

0 个答案:

没有答案