使用 react hooks 提交失败后恢复表单提交状态

IT技术 reactjs
2021-05-04 06:22:45

如果表单提交失败,我想恢复表单状态。这是关于在 reactjs 中防止多个表单提交的后续问题

const useCbOnce = (cb) => {
    const [called, setCalled] = useState(false);

    // Below can be wrapped in useCallback whenever re-renders becomes a problem
    return (e) => {
        if (!called) {
            setCalled(true);
            cb(e);
        }
    }
}

const MyForm = (props) => {
    const [name, setName] = useState();
    const handleSubmit = useCbOnce((e) => {
        e.preventDefault()
        if (name) {
            //all is good
        } else {
            console.log('please enter the name and submit again')
            // name is empty I need to restore the form state to allow the user to set and resubmit
        }
        console.log('submitted!')
    });
    return <form onSubmit={ handleSubmit }><input onChange={ (e) => setName(e.target.value) } /></form>;
}

假设我提交了一个表单而不设置名称!我想恢复以前的表单状态,以便 usr 可以填写名称并重新提交表单。基本上再次调用setCalled(false)但不确定在哪里做。

2个回答

您可以修改自定义钩子,使用回调的返回值来决定提交是成功还是失败。有了这个返回值,钩子可以在第一次成功调用后停止允许提交。

const useCbOnceOrRetryOnFail = (cb) => {
    const [succeeded, setSucceeded] = useState(false);

    return (e) => {
        if (!succeeded) {
            setSucceeded(cb(e));
        }
    }
}

// Usage:
const handleSubmit = useCbOnceOrRetryOnFail((e) => {
    e.preventDefault()
    if (!name) {
       console.log('please enter the name and submit again')
       return false; // Remember to set to false whenever fails
   }
   console.log('submitted!')
   return true;
});

使用异步回调:

const useCbOnceOrRetryOnFail = cb => {
  const [success, setSuccess] = useState(false);

  return e => {
    if (!success) {
      setSuccess(true);
      cb(e, setSuccess);
    } else {
      e.preventDefault(); // Still need to preventDefault if clicked again
    }
  };
};

  const handleSubmit = useCbOnceOrRetryOnFail((e, setSuccess) => {
    e.preventDefault();
    if (!name) {
      console.log("please enter the name and submit again");
      setSuccess(false); // Remember to set to false whenever fails
    } else {
      console.log("submitted!");
       authenticate.then(() => {
         setSuccess(true);
       }).catch(() => {
         setSuccess(false);
       });
    }
  });

请注意,我们需要传递setSuccess回调而不是简单地返回。这是因为调用 api 是异步的,我们需要在它被解决/拒绝时更新成功状态。

您可以同时useCbOnce返回一个once函数和一个reset函数:

const useCbOnce = () => {
    const [called, setCalled] = useState(false);

    return {
      // Below can be wrapped in useCallback whenever re-renders becomes a problem
      once: (cb) => (e) => {
        if (!called) {
            setCalled(true);
            cb(e);
        }
      },
      reset: () => setCalled(false);
    }
}

const MyForm = (props) => {
    const [name, setName] = useState();
    const { cbOnce, reset } = useCbOnce();

    const handleSubmit = cbOnce((e) => {
        e.preventDefault()
        if (name) {
            console.log('submitted!')
            //all is good
        } else {
            console.log('please enter the name and submit again')
            reset();
        }
    });

    return (
      <form onSubmit={handleSubmit}>
        <input onChange={e => setName(e.target.value)} />
      </form>
    );
}