score:4

Don't forget useRef as a possibility in situations like this - useState and useEffect have their place of course, but your logic to track and manage the state can be a bit of a pain, as well as causing probable unnecessary re-renders of your component (when that state doesn't form part of the render output). As an example from the OP:

import React, { useState, useRef } from 'react';

export default function Signup() {
  const [terms, setTerms] = useState('');
  const termsValidation = useRef(false);

  function handleSubmit(e) {
    e.preventDefault();

    if (!terms && !termsValidation.current) {
      termsValidation.current = true;
      console.log('run something here');
      termsValidation.current = false; // when its finished running
    }
 }

  return (
    <div> etc
  );
}

score:19

Changing state like setTermsValidation is asynchronous action which means it's not immediate and the program does not wait for it. It fires and forgets. Hence, when you call setTermsValidation(true) the program will continue run the next block instead of waiting termValidation to change to be true. That's why termsValidation will still have the old value.

You can just do this

function handleSubmit(e) {
    e.preventDefault();

    if (!terms) {
      setTermsValidation(true);
    } else {
      setTermsValidation(false);
      // assuming you want to run something when termsvalidation turn to false
      console.log('run something here');
    }
}

Or ideally use hooks useEffect()

useEffect(() => {
    if (!termsValidation) {
      console.log('run something here');
    }
}, [termsValidation]);

However, be careful because useEffect also runs on initial render.

score:29

The useState hook is asynchronous but it doesn't have a callback api like setState does. If you want to wait for a state update you need a useEffect hook:

import React, { useState, useEffect } from 'react';

export default function Signup() {
  const [terms, setTerms] = useState('');
  const [termsValidation, setTermsValidation] = useState(false);

  useEffect(() => {
    if (!termsValidation) {
      console.log('run something here');
    }
  }, [termsValidation]);

  function handleSubmit(e) {
    e.preventDefault();

    if (!terms) {
      setTermsValidation(true);
    } else {
      setTermsValidation(false);
    }
  }

  return (
    <div>
      <form>
        <input type="checkbox" id="terms" name="terms" checked={terms} />

        <button type="submit" onClick={handleSubmit}>
          Sign up
        </button>
      </form>
    </div>
  );
}

Related Query

More Query from same tag