You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native useState管理表单字段对象:解构获取字段值与类型遇阻求助

Solution to Your Form Field Validation Object Issue

First off, I spot a small typo in your setter function that’s probably throwing things off—you don’t need square brackets around text and colType when updating state. Let’s fix that first, then walk through how to handle validation smoothly with your combined state structure.

Step 1: Fix the State Setter

Your current code wraps text and colType in arrays unnecessarily, which breaks destructuring later. Update your setter to this clean version:

setValues({
  ...values,
  [name]: { text, colType } // Shorthand for { text: text, colType: colType }
});

This properly assigns the actual values to each field’s text and colType properties, making them easy to access later.

Step 2: Validate Fields on Submit

To validate each field based on its colType, loop through your values object during the submit handler. You can destructure each field’s properties directly while looping, then apply type-specific validation rules.

Complete Example Component

Here’s a reusable generic form component that implements this approach:

import { useState } from 'react';

const GenericForm = () => {
  // Initialize form state with field values and types
  const [values, setValues] = useState({
    fName: { text: 'John', colType: 'text' },
    lName: { text: 'Doe', colType: 'text' },
    hairColor: { text: 'Brown', colType: 'text' },
    birthDate: { text: '2010-02-02', colType: 'date' },
    email: { text: '', colType: 'email' }
  });
  
  // Track validation errors (optional but user-friendly)
  const [errors, setErrors] = useState({});

  // Type-specific validation logic
  const validateField = (text, colType) => {
    switch(colType) {
      case 'email':
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return emailRegex.test(text) ? null : 'Please enter a valid email';
      case 'date':
        return !isNaN(new Date(text).getTime()) ? null : 'Please enter a valid date';
      case 'text':
        return text.trim().length > 0 ? null : 'This field cannot be empty';
      default:
        return null;
    }
  };

  const handleChange = (e) => {
    const { name, value } = e.target;
    // Reuse the existing colType since it doesn't change after initialization
    const colType = values[name].colType;
    setValues(prev => ({
      ...prev,
      [name]: { text: value, colType }
    }));
    // Clear error for the field when user types
    if (errors[name]) setErrors(prev => ({ ...prev, [name]: null }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    let isFormValid = true;
    const newErrors = {};

    // Loop through all fields to validate
    Object.entries(values).forEach(([fieldName, { text, colType }]) => {
      const error = validateField(text, colType);
      if (error) {
        isFormValid = false;
        newErrors[fieldName] = error;
      }
    });

    if (isFormValid) {
      // Submit your form data here
      console.log('Form submitted successfully:', values);
    } else {
      // Show validation errors to the user
      setErrors(newErrors);
    }
  };

  return (
    <form onSubmit={handleSubmit} style={{ maxWidth: '300px', margin: '2rem auto' }}>
      {Object.entries(values).map(([fieldName, { text, colType }]) => (
        <div key={fieldName} style={{ marginBottom: '1rem' }}>
          <label htmlFor={fieldName} style={{ display: 'block', marginBottom: '0.5rem' }}>
            {fieldName.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase())}
          </label>
          <input
            type={colType === 'date' ? 'date' : 'text'}
            id={fieldName}
            name={fieldName}
            value={text}
            onChange={handleChange}
            style={{ width: '100%', padding: '0.5rem' }}
          />
          {errors[fieldName] && <span style={{ color: 'red', fontSize: '0.8rem' }}>{errors[fieldName]}</span>}
        </div>
      ))}
      <button type="submit" style={{ padding: '0.5rem 1rem', cursor: 'pointer' }}>Submit</button>
    </form>
  );
};

export default GenericForm;

Key Details to Note:

  • Destructuring Made Easy: Using Object.entries(values) lets us loop through each field and destructure text and colType directly in the callback (([fieldName, { text, colType }])), so you don’t have to jump through hoops to access these values.
  • Reusable ColType: In handleChange, we grab the existing colType from state since field types don’t change after initialization—no need to pass it around every time the input updates.
  • Scalable Validation: The validateField function uses a switch case, so adding new field types (like password or number) is as simple as adding a new case with your custom validation logic.

内容的提问来源于stack exchange,提问作者David Hash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 18:54:05