【问题标题】:Ref issue using react-hook-form使用 react-hook-form 引用问题
【发布时间】:2020-08-10 15:28:19
【问题描述】:

我正在尝试在我当前的项目中使用react-hook-form 创建表单验证。我已经尝试过不同的方法,但总是因为ref 属性而出错。如果我将<FormField> 更改为input,它就会开始工作。 知道如何解决这个问题吗?

联系方式

import React from 'react';
import { useForm } from "react-hook-form";
import FormField from '../../components/FormField';
import Button from '../../components/Button';

const Contact = () => {
    const { handleSubmit, register, errors } = useForm();
    const onSubmit = values => console.log(values);

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <FormField
                name="email"
                onChange={() => { console.log("changed!") }}
                ref={register({
                    required: "Required",
                    pattern: {
                        value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
                        message: "invalid email address"
                    }
                })}
            />
            <p style={{ color: "red" }}>
                {errors.email && errors.email.message}
            </p>


            <Button>Submit</Button>
        </form>
    );
};

export default Contact;

表单域

import React from "react";
import PropTypes from "prop-types";
import styled, { css } from "styled-components";


const FormFieldWrapper = styled.div`
  position: relative;
  textarea {
    min-height: 150px;
  }
  input[type="color"] {
    padding-left: 67px;
  }
`;

const Label = styled.label``;

Label.Text = styled.span`
  color: #e5e5e5;
  height: 57px;
  position: absolute;
  top: 0;
  left: 16px;

  display: flex;
  align-items: center;

  transform-origin: 0% 0%;
  font-size: 18px;
  font-style: normal;
  font-weight: 300;

  transition: 0.1s ease-in-out;
`;

const Input = styled.input`
  background: #53585d;
  color: #f5f5f5;
  display: block;
  width: 100%;
  height: 57px;
  font-size: 18px;

  outline: 0;
  border: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid #53585d;

  padding: 16px 16px;
  margin-bottom: 45px;

  resize: none;
  border-radius: 4px;
  transition: border-color 0.3s;

  &:focus {
    border-bottom-color: var(--primary);
  }
  &:focus:not([type="color"]) + ${Label.Text} {
    transform: scale(0.6) translateY(-10px);
  }
  ${({ value }) => {
    const hasValue = value.length > 0;
    return (
      hasValue &&
      css`
        &:not([type="color"]) + ${Label.Text} {
          transform: scale(0.6) translateY(-10px);
        }
      `
    );
  }}
`;

function FormField({ label, type, name, value, onChange, ref }) {
  const isTypeTextArea = type === "textarea";
  const tag = isTypeTextArea ? "textarea" : "input";
  return (
    <FormFieldWrapper>
      <Label>
        <Input
          as={tag}
          type={type}
          value={value}
          name={name}
          onChange={onChange}
          ref={ref}
        />
        <Label.Text>{label}:</Label.Text>
      </Label>
    </FormFieldWrapper>
  );
}

FormField.defaultProps = {
  type: "text",
  value: "",
};

FormField.propTypes = {
  label: PropTypes.string,
  name: PropTypes.string.isRequired,
  type: PropTypes.string,
  value: PropTypes.string,
  onChange: PropTypes.func,
  ref: PropTypes.func
};

export default FormField;

错误:

【问题讨论】:

    标签: reactjs react-hooks react-props react-hook-form


    【解决方案1】:

    参考docs,寄存器应该如下使用,这样我们就不会遇到参考问题,而且寄存器会改变输入中的值,所以我们不需要传递价值道具:

    联系方式:

    import React from "react";
    import { useForm } from "react-hook-form";
    import FormField from "../../components/FormField";
    import Button from "../../components/Button";
    
    const Contact = () => {
      const { handleSubmit, register, errors } = useForm();
      const onSubmit = (values) => console.log("values", values);
    
      return (
        <form onSubmit={handleSubmit(onSubmit)}>
          <FormField
            name="email"
            onChange={() => {
              console.log("changed!");
            }}
            register={register}
          />
          <p style={{ color: "red" }}>{errors.email && errors.email.message}</p>
    
          <Button>Submit</Button>
        </form>
      );
    };
    
    export default Contact;
    

    表单域:

    import React from "react";
    import PropTypes from "prop-types";
    import styled, { css } from "styled-components";
    
    const FormFieldWrapper = styled.div`
      position: relative;
      textarea {
        min-height: 150px;
      }
      input[type="color"] {
        padding-left: 67px;
      }
    `;
    
    const Label = styled.label``;
    
    Label.Text = styled.span`
      color: #e5e5e5;
      height: 57px;
      position: absolute;
      top: 0;
      left: 16px;
    
      display: flex;
      align-items: center;
    
      transform-origin: 0% 0%;
      font-size: 18px;
      font-style: normal;
      font-weight: 300;
    
      transition: 0.1s ease-in-out;
    `;
    
    const Input = styled.input`
      background: #53585d;
      color: #f5f5f5;
      display: block;
      width: 100%;
      height: 57px;
      font-size: 18px;
    
      outline: 0;
      border: 0;
      border-top: 4px solid transparent;
      border-bottom: 4px solid #53585d;
    
      padding: 16px 16px;
      margin-bottom: 45px;
    
      resize: none;
      border-radius: 4px;
      transition: border-color 0.3s;
    
      &:focus {
        border-bottom-color: var(--primary);
      }
      &:focus:not([type="color"]) + ${Label.Text} {
        transform: scale(0.6) translateY(-10px);
      }
      ${({ value = {} }) => { // here you should find an other approch because there is no value props
        const hasValue = value.length > 0;
        return (
          hasValue &&
          css`
            &:not([type="color"]) + ${Label.Text} {
              transform: scale(0.6) translateY(-10px);
            }
          `
        );
      }}
    `;
    
    const FormField = ({ label, type, name, onChange, register }) => {
      const isTypeTextArea = type === "textarea";
      const tag = isTypeTextArea ? "textarea" : "input";
      return (
        <FormFieldWrapper>
          <Label>
            <Input
              as={tag}
              type={type}
              //   value={value} it's not a controlled input! so the register'ill provide the value
              name={name}
              onChange={onChange}
              ref={register({
                required: "Required",
                pattern: {
                  value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
                  message: "invalid email address",
                },
              })}
            />
            <Label.Text>{label}:</Label.Text>
          </Label>
        </FormFieldWrapper>
      );
    };
    
    FormField.defaultProps = {
      type: "text",
      value: "",
    };
    
    FormField.propTypes = {
      label: PropTypes.string,
      name: PropTypes.string.isRequired,
      type: PropTypes.string,
      value: PropTypes.string,
      onChange: PropTypes.func,
      ref: PropTypes.func,
    };
    
    export default FormField;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-10
      • 1970-01-01
      • 2021-09-23
      • 2022-12-21
      • 2021-11-21
      • 1970-01-01
      • 2022-01-25
      • 2021-05-08
      相关资源
      最近更新 更多