Page not re-rendering after hook state update

functional component not 're rendering on state change
force render hook
useref not updating
react hooks usestate not 're rendering
useeffect
react, ( usestate not updating)
react hooks re-render on props change
react hooks not working

The page renders the input correctly, however errors only seem to appear on the second render even though they are displayed is useForm state on the first render.

So for the password field I enter a single character and the state of useForm changes to {password: "Must be at.....} but the screen does not update to display errors.password until I enter in another character.

// 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
}```



I can appreciate that it's of interest to work on a custom hook but forms are ubiquitous and there are solid, proven means to work with them. IMHO Formik is probably the best.

With the three fields that you have there, you could implement something like the following:

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>
);

Note that the above is just from memory - which to some extent speaks to it's simplicity. As initialValues are supplied to Formik, you can build complex component hierarchies without having to pass down form state but that's just one of the various benefits.

React useState Hook don't rerender the changes · Issue #15595 , Also, the state of a class component must be an object and supports shallow merging during updates. Contrastingly, useState does not require  The function is working properly, changing the schools' state; I can see that from the console, but the elements are not re-rendering. I think this is because React doesn't re-render components when the value hasn't changed, but can't figure out a way to re-render the elements since the order changed.


I have an assumption.

In registerFormValidation doesn't modify errors object. Create a new each time.

React Hooks - Understanding Component Re-renders, When I started working on React Hooks, the official documentation Context value is updated (if the component listens to context change using We have seen the component re-render cycle due to the local state Note: cleanup handler didn't run yet (since no useEffect handler calls ran earlier). #5: New  The word "reducer" evokes images of Redux for many - but you don't have to understand Redux to read this post, or to use the new useReducer hook that comes with the React 16. componentDidMount fires and set's state immediately (not in an async callback) The state change means render() is called again and returns new JSX which replaces the


FIXED:

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;

got rid of useEffect!

How does React Hooks re-renders a function Component?, I could not comprehend how invoking the function returned by a hook, was triggering a re-render. state and re-renders the component on state updates but the usage instance.render(); // reset the callId after every render useState hook is the primary building block which enables functional components to hold state between re-renders. Let’s understand the workings of useState with an example. We will implement the


useRef vs useState: Should we re-render or not?, not. Both useState and useRef remembers their data after a re-render With these new Hooks API's, we have an extra layer of question marks etc end up updating the state which in turn triggers a re-rendering process. Right after creating a new task I call this method "handleClose" that will update my state variable "this.state.acoes" again: [code] handleCloseAcao(){ this.atualizar() } Now… Here is where the problem happens. Right after calling that method, my state variable got updated, but the component is not rendering the new data it is receiving.


A guide to useState in React, How do you're render a component in react when state changes? However, you might still be wondering why React doesn’t just update this.state immediately without re-rendering. There are two main reasons: This would break the consistency between props and state, causing issues that are very hard to debug. This would make some of the new features we’re working on impossible to implement.


How does React decide to re-render a component?, Can't perform a React state update on an unmounted component This is a no op? One of the most common reasons that your components might not be re-rendering is that you're modifying the existing state in your reducer instead of returning a new copy of state with the necessary changes (check out the Troubleshooting section). When you mutate the existing state directly, Redux doesn't detect a difference in state and won't notify your components that the store has changed.