【问题标题】:React form how to get user data based on a toggle on/off反应表单如何基于切换开/关获取用户数据
【发布时间】:2021-12-29 18:16:16
【问题描述】:

我在 React JS 中有一个带有一个切换/开关的表单。如果拨动/开关打开,则屏幕上会出现两个输入。因此,如果用户输入输入并且切换/开关打开并保持打开状态,我想获取用户数据。因此,如果用户输入输入,但他再次切换/切换为关闭,则输入​​值将被重置,当他保存表单时,我必须获得空的用户数据(我得到初始值)。我怎样才能实现这样的目标?如果切换按钮为 false 并且我将 usestate 设置为初始值,我正在检查提交处理程序,但它不起作用。

我的代码:

Form.js

import React, { useRef, useState } from "react";
import Wrapper from "./UI/Wrapper";
import Switch from '@mui/material/Switch';
import "./Form.css";

const Form = () => {

  const [showCertification, setShowCertification] = useState(false);
  
  const [enteredCodecert, setEnteredCodecert] = useState('');
  const codecertRef = useRef();

  const [codesteps, setCodesteps] = useState([{ value: null }]);
  const codestepsRef = useRef();

  const enteredCodecertIsValid = showCertification && enteredCodecert.trim() !== '';
  const codecertInputIsInvalid = !enteredCodecertIsValid;

  const codestepsIsValid = showCertification && codesteps.length >= 1 && codesteps.every(codestep => codestep.value !== null && codestep.value.trim() !== '');
  const codestepInputIsInvalid = !codestepsIsValid;


  const showCertificationHandler = (event) => {
    setShowCertification(prevState => !prevState);
    if (!showCertification) {
      setEnteredCodecert('');
      setCodesteps([{value: null}]);
    }
  }

  const codecertChangeHandler = (event) => {
    setEnteredCodecert(event.target.value);
  }

  const stepChangeHandler = (i, event) => {
    const values = [...codesteps];
    values[i].value = event.target.value;
    setCodesteps(values);
  }

  const addStepHandler = (event) => {
    event.preventDefault();
    const values = [...codesteps];
    values.push({ value: null });
    setCodesteps(values);
  }

  const removeStepHandler = (i, event) => {
    event.preventDefault();
    const values = [...codesteps];
    values.splice(i, 1);
    setCodesteps(values);
  }

  const submitHandler = (event) => {
    event.preventDefault();

    if (!enteredCodecertIsValid && showCertification) {
      codecertRef.current.focus();
      return;
    }

    if (!codestepsIsValid && showCertification) {
      if (codesteps.length >= 1) {
        codestepsRef.current.focus();
        return;
      }
      return;
    }

    if (showCertification === false) {
      setEnteredCodecert('');
      setCodesteps([{value: null}]);
    }

    console.log(enteredCodecert);
    console.log(codesteps);
  }


  return (
    <Wrapper>
      <form onSubmit={submitHandler}>

        <fieldset className={`${(showCertification && codecertInputIsInvalid) || (showCertification && codestepInputIsInvalid)  ? 'govgr-form-group__error' : '' }`}>
          <legend><h3 className="govgr-heading-m">Certifications</h3></legend>

          <Switch id="certification" checked={showCertification} onClick={showCertificationHandler} inputProps={{ 'aria-label': 'controlled' }} />
          <label className="govgr-label govgr-!-font-weight-bold cert-label" htmlFor="certification">Certification</label>
          {showCertification && (
          <div>
            <div className="govgr-form-group">
              <label className="govgr-label govgr-!-font-weight-bold" htmlFor="codecert">Code Certification*</label>
              {codecertInputIsInvalid && <p className="govgr-error-message"><span className="govgr-visually-hidden">Λάθος:</span>Code Certification is required.</p>}
              <input className={`govgr-input govgr-!-width-three-quarter ${codecertInputIsInvalid ? 'govgr-error-input' : ''}`} id="codecert" name="codecert" type="text" value={enteredCodecert} ref={codecertRef} onChange={codecertChangeHandler} />
           </div>

            <div className="govgr-form-group">
              <label className="govgr-label govgr-!-font-weight-bold" htmlFor="codestep">Code STEPS*</label>
              {codestepInputIsInvalid && <p className="govgr-error-message"><span className="govgr-visually-hidden">Λάθος:</span>Code STEPS are required.</p>}
                  {codesteps.map((field, idx) => {
                    return (
                    <div key={`${field}-${idx}`}>
                      <div className="flex-row">
                        <input className={`govgr-input govgr-input--width-10 input-step ${codestepInputIsInvalid ? 'govgr-error-input' : ''}`} id="codestep" type="text" ref={codestepsRef} value={field.value || ""} onChange={e => stepChangeHandler(idx, e)} />
                        <button className="govgr-btn govgr-btn-warning remove-step" onClick={(e) => removeStepHandler(idx, e)}>Χ</button>
                      </div>  
                    </div>
                    );
                  })}
                  <button className="govgr-btn govgr-btn-secondary button-step" onClick={addStepHandler}>Add Code Step</button>       
            </div>
          </div>
          )}
        </fieldset>

        <button className="govgr-btn govgr-btn-primary btn-center" type="submit">Save</button>

      </form>
    </Wrapper>
  );
};

export default Form;

【问题讨论】:

    标签: javascript reactjs forms react-hooks use-state


    【解决方案1】:

    问题在于,在showCertificationHandler 中,当您切换showCertification 时,您期望状态更新是即时的。

    const showCertificationHandler = (event) => {
      setShowCertification(prevState => !prevState);
      if (!showCertification) {
        setEnteredCodecert('');
        setCodesteps([{value: null}]);
      }
    }
    

    但是,React 状态更新并非如此。 React 状态更新被排队并异步处理。

    要解决此问题,请将“重置”逻辑移动到依赖于 showCertification 状态的 useEffect 挂钩中。

    const showCertificationHandler = () => {
      setShowCertification((prevState) => !prevState);
    };
    
    useEffect(() => {
      if (!showCertification) {
        setEnteredCodecert("");
        setCodesteps([{ value: null }]);
      }
    }, [showCertification]);
    

    出于与上述相同的原因,当重置 submitHandler 中的状态时,它们会被排队并异步处理,因此控制台记录状态后立即只会记录当前渲染周期中的状态值,而不是它们将是什么在随后的渲染周期中。您可以从submitHandler 中删除“重置”逻辑。

    const submitHandler = (event) => {
      event.preventDefault();
    
      if (!enteredCodecertIsValid && showCertification) {
        codecertRef.current.focus();
        return;
      }
    
      if (!codestepsIsValid && showCertification) {
        if (codesteps.length >= 1) {
          codestepsRef.current.focus();
          return;
        }
        return;
      }
    
      console.log({enteredCodecert, codesteps});
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-17
      • 1970-01-01
      • 1970-01-01
      • 2018-06-28
      相关资源
      最近更新 更多