挂钩状态更新后页面未重新呈现

时间:2019-10-08 22:46:30

标签: reactjs react-hooks

页面正确地呈现了输入,但是错误似乎仅出现在第二个呈现器上,即使它们在第一个呈现器上显示为useForm状态也是如此。

因此,对于密码字段,我输入一个字符,并且useForm的状态更改为{password: "Must be at.....},但是直到我输入另一个字符后,屏幕才会更新为显示errors.password

// nodejs library that concatenates classes
// reactstrap components
import {
  Button,
  Card,
  CardBody,
  CardHeader,
  Col,
  Container,
  Form,
  FormFeedback,
  FormGroup,
  Input,
  Row
} from "reactstrap";
import {register} from "apiCalls/AuthRequests";
import useForm from "hooks/AuthHooks";
import {registerFormValidation} from "components/validation/AuthFormValidation";

function RegisterForm(props) {
  const [loading, setLoading] = useState(false);
  const {values, handleChange, handleSubmit, errors, setErrors} = useForm(submit, registerFormValidation);

  const emailRef = useRef(null);
  const passwordRef = useRef(null);
  const accessCodeRef = useRef(null);

  async function submit() {
    setLoading(true);
    const response = await register(values.email, values.password, values.accessCode);
    if (response.ok) {
    } else if (response.status === 422) {
      if ("access_code" in response.data) {
        accessCodeRef.current.focus();
        setErrors({accessCode: response.data.access_code});
      }
      if ("email" in response.data) {
        setErrors({email: response.data.email});
        emailRef.current.focus();
      }
      if ("password" in response.data) {
        setErrors({password: response.data.password});
        passwordRef.current.focus();
      }
    }
    setLoading(false)
  }
  useEffect(() => {
    console.log(errors);
    });

    return (
      <>
        <div className="content">
          <Container className="pb-5">
            <Row>
              <Col lg="6" md="8" className="ml-auto mr-auto">
                <Card className="bg-secondary border-0">
                  <CardHeader className="bg-transparent">
                    <div className="text-center">
                      <h2>Register</h2>
                    </div>
                  </CardHeader>
                  <CardBody className="px-lg-5 py-lg-5">
                    <Form role="form" onSubmit={handleSubmit}>
                      <FormGroup>
                        <label
                          className="form-control-label"
                        >
                          Email
                        </label>
                        <Input
                          name="email"
                          type="email"
                          innerRef={emailRef}
                          value={values.email || ""}
                          onChange={handleChange}
                          invalid={!!errors.email}
                          required
                        />
                        <FormFeedback>{errors.email}</FormFeedback>
                      </FormGroup>
                      <FormGroup>
                        <label
                          className="form-control-label"
                        >
                          Password
                        </label>
                        <Input
                          name="password"
                          type="password"
                          innerRef={passwordRef}
                          value={values.password || ""}
                          onChange={handleChange}
                          invalid={!!errors.password}
                          required
                        />
                        <FormFeedback>{errors.password}</FormFeedback>
                      </FormGroup>
                      <FormGroup>
                        <label
                          className="form-control-label"
                        >
                          Access Code
                        </label>
                        <Input
                          name="accessCode"
                          type="text"
                          innerRef={accessCodeRef}
                          value={values.accessCode || ''}
                          onChange={handleChange}
                          invalid={!!errors.accessCode}
                          required
                        />
                        <FormFeedback>{errors.accessCode}</FormFeedback>
                      </FormGroup>
                      <Row className="my-4">
                        <Col xs="12">
                          <div
                            className="custom-control custom-control-alternative custom-checkbox">
                            <input
                              className="custom-control-input"
                              id="customCheckRegister"
                              type="checkbox"
                              required
                            />
                            <label
                              className="custom-control-label"
                              htmlFor="customCheckRegister"
                            >
                            <span className="text-muted">
                              I agree with the{" "}
                              <a
                                href=""
                                target="_blank"
                                rel="noopener noreferrer"
                              >
                                Privacy Policy
                              </a>
                            </span>
                            </label>
                          </div>
                        </Col>
                      </Row>
                      <div className="text-center">
                        <Button disabled={loading} className="mt-4" color="info" type="submit">
                          Create account
                        </Button>
                      </div>
                    </Form>
                  </CardBody>
                </Card>
              </Col>
              <Col md="4" className="ml-auto mr-auto">
                <h2>Being a photographer is easier with <b className="text-primary">FOCAL</b></h2>
                <ul>
                  <li>
                    <h4>Focal is great</h4>
                  </li>
                  <li>
                    <h4>Save time</h4>
                  </li>
                  <li>
                    <h4>More customers</h4>
                  </li>
                </ul>
              </Col>
            </Row>
          </Container>
        </div>
      </>
    );
}

export default RegisterForm;

const useForm = (callback, validate) => {

  const [values, setValues] = useState({});
  const [errors, setErrors] = useState({});
  const [isSubmitting, setIsSubmitting] = useState(false);


  const handleSubmit = (event) => {
    if (event) event.preventDefault();
    setIsSubmitting(true);
  };

  useEffect(() => {
    if (Object.keys(errors).length === 0 && isSubmitting) {
      callback();
      setIsSubmitting(false);
    }
  }, [callback, errors, isSubmitting]);

  useEffect(() => {
    setErrors(validate(values, errors));
  }, [validate, values, errors]);

  const handleChange = (event) => {
    event.persist();
    setValues(values => ({...values, [event.target.name]: event.target.value}));
    setErrors(validate(values, errors));
  };

  return {
    handleChange,
    handleSubmit,
    setErrors,
    values,
    errors
  }
};

export default useForm;

export function registerFormValidation(values, errors) {
  if (values.email === ""){
    delete errors.email;
  }
  if (values.password) {
    if (!verifyLength(values.password, PASSWORD_LENGTH)){
      errors.password = "Password must be greater than 8 Characters";
    } else {
      delete errors.password;
    }
  }

  if (values.accessCode === "") {
    delete values.accessCode;
  }
  return errors
}```


3 个答案:

答案 0 :(得分:1)

我很高兴使用自定义钩子很有趣,但是表单无处不在,并且有可靠的可靠方法来使用它们。恕我直言Formik可能是最好的。

有了三个字段,您可以实现以下内容:

import React from 'react';
import { Formik } from 'formik';

const BasicExample = () => (
  <div>
    <Formik
      initialValues={{ email: '', password: '', accessCode: '' }}
      onSubmit={(values, actions) => {
        setTimeout(() => {
          alert(JSON.stringify(values, null, 2));
          actions.setSubmitting(false);
        }, 1000);
      }}
      render={props => (
        <form onSubmit={props.handleSubmit}>
          <input
            type="email"
            onChange={props.handleChange}
            onBlur={props.handleBlur}
            value={props.values.email}
            name="email"
          />
          {props.errors.email && <div id="feedback">{props.errors.email}</div>}
          <input
            type="password"
            onChange={props.handleChange}
            onBlur={props.handleBlur}
            value={props.values.password}
            name="password"
          />
          {props.errors.password && <div id="feedback">{props.errors.password}</div>}
          <input
            type="text"
            onChange={props.handleChange}
            onBlur={props.handleBlur}
            value={props.values.accessCode}
            name="accessCode"
          />
          {props.errors.accessCode && <div id="feedback">{props.errors.acessCode}</div>}
          <button type="submit">Submit</button>
        </form>
      )}
    />
  </div>
);

请注意,以上内容仅来自内存-从某种程度上讲,这很简单。当initialValues提供给Formik时,您可以构建复杂的组件层次结构而不必传递表单状态,但这只是各种好处之一。

答案 1 :(得分:0)

我有一个假设。

在registerFormValidation中不会修改错误对象。每次创建一个新的。

答案 2 :(得分:0)

已修复:

const useForm = (callback, validate) => {

  const [values, setValues] = useState({});
  const [errors, setErrors] = useState({});


  const handleSubmit = (event) => {
    if (event) event.preventDefault();
    if (Object.keys(errors).length === 0){
      callback();
    }
  };

  const handleChange = (event) => {
    event.persist();
    setValues(values => ({...values, [event.target.name]: event.target.value}));
    setErrors(validate({[event.target.name]: event.target.value}, errors));
  };

  return {
    handleChange,
    handleSubmit,
    setErrors,
    values,
    errors
  }
};

export default useForm;

摆脱useEffect!