表单processing

LearningReact表单processing, including受控component, 非受控component, 表单verification, 表单submittingetc. in 容

1. 受控component

in Reactin, 受控component is 指由Reactstatus控制其值 表单元素. 当user输入时, 表单元素 值会updateReactstatus, 而Reactstatus又控制着表单元素 显示值.

function ControlledForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: ''
  });
  
  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData(prevState => ({
      ...prevState,
      [name]: value
    }));
  };
  
  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('表单data:', formData);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="name">姓名: </label>
        <input 
          type="text" 
          id="name" 
          name="name" 
          value={formData.name} 
          onChange={handleChange} 
        />
      </div>
      <div>
        <label htmlFor="email">邮箱: </label>
        <input 
          type="email" 
          id="email" 
          name="email" 
          value={formData.email} 
          onChange={handleChange} 
        />
      </div>
      <div>
        <label htmlFor="password">password: </label>
        <input 
          type="password" 
          id="password" 
          name="password" 
          value={formData.password} 
          onChange={handleChange} 
        />
      </div>
      <button type="submit">submitting</button>
    </form>
  );
}

提示

受控component 优点 is 表单data完全由Reactstatus控制, 便于implementation表单verification and 实时反馈.

2. 非受控component

非受控component is 指由DOM本身控制其值 表单元素, React不直接控制其值, 而 is throughref来访问DOM元素 值.

function UncontrolledForm() {
  const nameRef = useRef(null);
  const emailRef = useRef(null);
  const passwordRef = useRef(null);
  
  const handleSubmit = (e) => {
    e.preventDefault();
    const formData = {
      name: nameRef.current.value,
      email: emailRef.current.value,
      password: passwordRef.current.value
    };
    console.log('表单data:', formData);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="name">姓名: </label>
        <input type="text" id="name" ref={nameRef} />
      </div>
      <div>
        <label htmlFor="email">邮箱: </label>
        <input type="email" id="email" ref={emailRef} />
      </div>
      <div>
        <label htmlFor="password">password: </label>
        <input type="password" id="password" ref={passwordRef} />
      </div>
      <button type="submit">submitting</button>
    </form>
  );
}

warning

非受控component using场景较 few , 一般只 in 需要直接operationDOM or migration现 has code时using.

3. 表单verification

表单verification is 确保user输入data符合要求 important 步骤. Reactin可以throughstatusmanagement and 条件渲染implementation表单verification.

function ValidatedForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: ''
  });
  
  const [errors, setErrors] = useState({});
  
  const validate = () => {
    const newErrors = {};
    
    if (!formData.name.trim()) {
      newErrors.name = '姓名不能 for 空';
    }
    
    if (!formData.email.trim()) {
      newErrors.email = '邮箱不能 for 空';
    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
      newErrors.email = '邮箱格式不正确';
    }
    
    if (!formData.password) {
      newErrors.password = 'password不能 for 空';
    } else if (formData.password.length < 6) {
      newErrors.password = 'password long 度不能 few 于6位';
    }
    
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };
  
  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData(prevState => ({
      ...prevState,
      [name]: value
    }));
    
    // 实时清除 for 应字段 errorinformation
    if (errors[name]) {
      setErrors(prevErrors => {
        const newErrors = { ...prevErrors };
        delete newErrors[name];
        return newErrors;
      });
    }
  };
  
  const handleSubmit = (e) => {
    e.preventDefault();
    if (validate()) {
      console.log('表单data:', formData);
    }
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="name">姓名: </label>
        <input 
          type="text" 
          id="name" 
          name="name" 
          value={formData.name} 
          onChange={handleChange} 
          className={errors.name ? 'error' : ''}
        />
        {errors.name && <p className="error-message">{errors.name}</p>}
      </div>
      <div>
        <label htmlFor="email">邮箱: </label>
        <input 
          type="email" 
          id="email" 
          name="email" 
          value={formData.email} 
          onChange={handleChange} 
          className={errors.email ? 'error' : ''}
        />
        {errors.email && <p className="error-message">{errors.email}</p>}
      </div>
      <div>
        <label htmlFor="password">password: </label>
        <input 
          type="password" 
          id="password" 
          name="password" 
          value={formData.password} 
          onChange={handleChange} 
          className={errors.password ? 'error' : ''}
        />
        {errors.password && <p className="error-message">{errors.password}</p>}
      </div>
      <button type="submit">submitting</button>
    </form>
  );
}

4. 表单submittingprocessing

表单submitting时, 通常需要processingdata发送 to server 逻辑. in Reactin, 可以usingasync/await or Promise来processingasynchronousrequest.

function SubmitForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: ''
  });
  
  const [errors, setErrors] = useState({});
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [submitSuccess, setSubmitSuccess] = useState(false);
  
  // verificationfunction...
  
  const handleSubmit = async (e) => {
    e.preventDefault();
    
    if (validate()) {
      setIsSubmitting(true);
      try {
        const response = await fetch('https://api.example.com/register', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(formData)
        });
        
        if (response.ok) {
          const data = await response.json();
          console.log('register成功:', data);
          setSubmitSuccess(true);
          // reset表单
          setFormData({ name: '', email: '', password: '' });
        } else {
          const errorData = await response.json();
          setErrors({
            submit: errorData.message || 'register失败, 请稍 after 重试'
          });
        }
      } catch (error) {
        setErrors({
          submit: 'networkerror, 请稍 after 重试'
        });
      } finally {
        setIsSubmitting(false);
      }
    }
  };
  
  return (
    <div>
      {submitSuccess && <p className="success-message">register成功!</p>}
      <form onSubmit={handleSubmit}>
        {/* 表单字段... */}
        {errors.submit && <p className="error-message">{errors.submit}</p>}
        <button type="submit" disabled={isSubmitting}>
          {isSubmitting ? 'submittingin...' : 'submitting'}
        </button>
      </form>
    </div>
  );
}

5. complex 表单processing

for 于package含复选框, 单选按钮, under 拉菜单etc. complex 表单, 可以usingclass似 方式processing.

function ComplexForm() {
  const [formData, setFormData] = useState({
    gender: 'male',
    hobbies: [],
    city: '',
    agree: false
  });
  
  const handleGenderChange = (e) => {
    setFormData(prevState => ({
      ...prevState,
      gender: e.target.value
    }));
  };
  
  const handleHobbyChange = (e) => {
    const { value, checked } = e.target;
    setFormData(prevState => {
      if (checked) {
        return {
          ...prevState,
          hobbies: [...prevState.hobbies, value]
        };
      } else {
        return {
          ...prevState,
          hobbies: prevState.hobbies.filter(hobby => hobby !== value)
        };
      }
    });
  };
  
  const handleCityChange = (e) => {
    setFormData(prevState => ({
      ...prevState,
      city: e.target.value
    }));
  };
  
  const handleAgreeChange = (e) => {
    setFormData(prevState => ({
      ...prevState,
      agree: e.target.checked
    }));
  };
  
  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('表单data:', formData);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>性别: </label>
        <div>
          <input 
            type="radio" 
            id="male" 
            name="gender" 
            value="male" 
            checked={formData.gender === 'male'} 
            onChange={handleGenderChange} 
          />
          <label htmlFor="male">男</label>
          <input 
            type="radio" 
            id="female" 
            name="gender" 
            value="female" 
            checked={formData.gender === 'female'} 
            onChange={handleGenderChange} 
          />
          <label htmlFor="female">女</label>
        </div>
      </div>
      
      <div>
        <label>爱 good : </label>
        <div>
          <input 
            type="checkbox" 
            id="reading" 
            name="hobbies" 
            value="reading" 
            checked={formData.hobbies.includes('reading')} 
            onChange={handleHobbyChange} 
          />
          <label htmlFor="reading">阅读</label>
          <input 
            type="checkbox" 
            id="sports" 
            name="hobbies" 
            value="sports" 
            checked={formData.hobbies.includes('sports')} 
            onChange={handleHobbyChange} 
          />
          <label htmlFor="sports">运动</label>
          <input 
            type="checkbox" 
            id="music" 
            name="hobbies" 
            value="music" 
            checked={formData.hobbies.includes('music')} 
            onChange={handleHobbyChange} 
          />
          <label htmlFor="music">音乐</label>
        </div>
      </div>
      
      <div>
        <label htmlFor="city">城市: </label>
        <select 
          id="city" 
          name="city" 
          value={formData.city} 
          onChange={handleCityChange} 
        >
          <option value="">请选择城市</option>
          <option value="beijing">北京</option>
          <option value="shanghai"> on 海</option>
          <option value="guangzhou">广州</option>
          <option value="shenzhen">深圳</option>
        </select>
      </div>
      
      <div>
        <input 
          type="checkbox" 
          id="agree" 
          name="agree" 
          checked={formData.agree} 
          onChange={handleAgreeChange} 
        />
        <label htmlFor="agree">我同意条款 and 条件</label>
      </div>
      
      <button type="submit">submitting</button>
    </form>
  );
}

6. using第三方libraryprocessing表单

for 于 complex 表单, 还可以using第三方librarysuch asFormik, React Hook Formetc.来简化表单processing.

// usingReact Hook Formexample
import { useForm } from 'react-hook-form';

function HookForm() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  
  const onSubmit = (data) => {
    console.log('表单data:', data);
  };
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="name">姓名: </label>
        <input 
          type="text" 
          id="name" 
          {...register('name', { required: '姓名不能 for 空' })} 
        />
        {errors.name && <p className="error-message">{errors.name.message}</p>}
      </div>
      <div>
        <label htmlFor="email">邮箱: </label>
        <input 
          type="email" 
          id="email" 
          {...register('email', {
            required: '邮箱不能 for 空',
            pattern: {
              value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
              message: '邮箱格式不正确'
            }
          })} 
        />
        {errors.email && <p className="error-message">{errors.email.message}</p>}
      </div>
      <button type="submit">submitting</button>
    </form>
  );
}

练习 1: creation受控表单

  1. creation一个package含姓名, 邮箱, 电话 受控表单
  2. implementation实时表单verification
  3. 添加submitting按钮, 点击时显示表单data

练习 2: processing complex 表单

  1. creation一个package含单选按钮, 复选框, under 拉菜单 complex 表单
  2. implementation表单verification
  3. 添加submitting按钮, 点击时显示表单data