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

Reactjs 钩子状态更新后页面未重新呈现,reactjs,react-hooks,Reactjs,React Hooks,页面正确呈现输入,但是错误似乎只出现在第二次呈现上,即使它们在第一次呈现时显示为useForm状态 因此,对于密码字段,我输入一个字符,使用状态将更改为{password:“必须在….},但屏幕不会更新以显示错误。密码,直到我输入另一个字符 // nodejs library that concatenates classes // reactstrap components import { Button, Card, CardBody, CardHeader, Col,

页面正确呈现输入,但是错误似乎只出现在第二次呈现上,即使它们在第一次呈现时显示为useForm状态

因此,对于密码字段,我输入一个字符,使用状态将更改为
{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;

我可以理解,使用自定义钩子很有趣,但是表单无处不在,并且有可靠的、经过验证的方法来使用它们。IMHO可能是最好的

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

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>
);
从“React”导入React;
从'Formik'导入{Formik};
常量基本示例=()=>(
{
设置超时(()=>{
警报(JSON.stringify(值,null,2));
动作。设置提交(错误);
}, 1000);
}}
render={props=>(
{props.errors.email&&{props.errors.email}
{props.errors.password&&{props.errors.password}
{props.errors.accessCode&&{props.errors.acescode}
提交
)}
/>
);
请注意,以上内容仅来自内存,这在某种程度上说明了它的简单性。由于
初始值
提供给Formik,您可以构建复杂的组件层次结构,而无需传递表单状态,但这只是各种好处之一。

我有一个假设

在注册表中,验证不会修改错误对象。每次都创建一个新对象。

修复:

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!

我相信我发现了问题。我需要使用refs来确保屏幕更新…我想。Gunna试试。
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>
);
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;