开发者问题收集

React-无法读取标签中显示的未定义错误的属性

2022-01-02
748

我正在创建一个表单来更新应用程序后端的患者对象。当我提交表单时,它给了我“TypeError:无法读取未定义的属性(读取'firstName')”,然后显示此信息

72 |   && <p className={styles.errMsg} name="errMsg" data-testid="errMsg">{constants.API_ERROR}</p>}
  73 | {patient && (
  74 | <form onSubmit={onSubmit}>
> 75 |   <label htmlFor="firstName">
     | ^  76 |     First Name:
  77 |     <input
  78 |       type="text"

如果有帮助,请链接到错误图片

我只在尝试读取尚未定义或未及时加载的对象的属性时遇到此错误。我不明白为什么这里会弹出此错误。

如果需要,我的整个页面的代码

/* eslint-disable react-hooks/exhaustive-deps */
import {
  useState, React, useEffect, useContext
} from 'react';
import { useHistory } from 'react-router-dom';
import constants from '../../utils/constants';
import { UserContext } from '../context/UserContext';
import styles from './PatientsPage.module.css';
import { createNewPatient } from './PatientsService';
import patientValidator from './PatientValidator';

const EditPatientPage= () => {
  const history = useHistory();
  const { loggedIn } = useContext(UserContext);
  const [formData, setFormData] = useState({
    firstName: '',
    lastName: '',
    age: '',
    insuranceProvider: '',
    email: '',
    height: '',
    weight: '',
    ssn: '',
    street1: '',
    street2: '',
    city: '',
    state: '',
    postal: '',
    gender: ''
  });
  const [errors, setErrors] = useState({
    firstName: '',
    roomTypeId: '',
    lastName: '',
    numberOfNights: ''
  });
  const [apiError, setApiError] = useState(false);
  const usStates = ['AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FL', 'GA', 'GU', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VI', 'VA', 'VI', 'WA', 'WV', 'WI', 'WY'];
  const genderOptions = ['Female', 'Male', 'Other'];

  const onChangeForInputs = (e) => {
    setFormData({ ...formData, [e.target.id]: e.target.value });
  };

  const onSubmit = async (e) => {
    e.preventDefault();
    setErrors(patientValidator(formData, setApiError));
    if (sessionStorage.getItem('isValid')) { await createNewPatient(formData).then(() => history.push('/patients')); }
  };

  useEffect(async () => {
    if (!loggedIn) {
      history.push('/');
    }
  }, []);

  return (
    <div className="inputContainer">
      {apiError
          && <p className={styles.errMsg} name="errMsg" data-testid="errMsg">{constants.API_ERROR}</p>}
      <form onSubmit={onSubmit}>
        <label htmlFor="firstName">
          First Name:
          <input type="text" id="firstName" name="firstName" className="input" onChange={onChangeForInputs} value={formData.firstName} />
        </label>
        {errors.firstName && (
          <>
            <span className={styles.error}>{errors.firstName}</span>
          </>
        )}
        <br />
        <label htmlFor="lastName">
          Last Name:
          <input type="text" id="lastName" name="lastName" className="input" onChange={onChangeForInputs} value={formData.lastName} />
        </label>
        {errors.lastName && (
          <>
            <span className={styles.error}>{errors.lastName}</span>
          </>
        )}
        <br />
        <label htmlFor="gender">
          Gender:
          <select name="gender" id="gender" className="input" onChange={onChangeForInputs} value={formData.gender}>
            <option value="" onChange={onChangeForInputs} />
            {genderOptions.map((gender) => (
              <option value={gender} onChange={onChangeForInputs}>{gender}</option>
            ))}
          </select>
        </label>
        {errors.state && (
        <>
          <span className={styles.error}>{errors.state}</span>
        </>
        )}
        <br />
        <label htmlFor="age">
          Age:
          <input type="number" id="age" name="age" className="input" onChange={onChangeForInputs} value={formData.age} />
        </label>
        {errors.age && (
          <>
            <span className={styles.error}>{errors.age}</span>
          </>
        )}
        <br />
        <label htmlFor="height">
          Height:
          <input type="number" id="height" name="height" className="input" onChange={onChangeForInputs} value={formData.height} />
        </label>
        {errors.height && (
          <>
            <span className={styles.error}>{errors.height}</span>
          </>
        )}
        <br />
        <label htmlFor="weight">
          Weight:
          <input type="number" id="weight" name="weight" className="input" onChange={onChangeForInputs} value={formData.weight} />
        </label>
        {errors.weight && (
          <>
            <span className={styles.error}>{errors.weight}</span>
          </>
        )}
        <br />
        <label htmlFor="ssn">
          Social Security Number:
          <input type="text" id="ssn" name="ssn" className="input" onChange={onChangeForInputs} value={formData.ssn} />
        </label>
        {errors.ssn && (
          <>
            <span className={styles.error}>{errors.ssn}</span>
          </>
        )}
        <br />
        <label htmlFor="street1">
          Street:
          <input type="text" id="street1" name="street1" className="input" onChange={onChangeForInputs} value={formData.street1} />
        </label>
        {errors.street1 && (
          <>
            <span className={styles.error}>{errors.street1}</span>
          </>
        )}
        <br />
        <label htmlFor="street2">
          Apartment/Unit # (if Patient has one):
          <input type="text" id="street2" name="street2" className="input" onChange={onChangeForInputs} value={formData.street2} />
        </label>
        {errors.street2 && (
          <>
            <span className={styles.error}>{errors.street2}</span>
          </>
        )}
        <br />
        <label htmlFor="city">
          City:
          <input type="text" id="city" name="city" className="input" onChange={onChangeForInputs} value={formData.city} />
        </label>
        {errors.city && (
          <>
            <span className={styles.error}>{errors.city}</span>
          </>
        )}
        <br />
        <label htmlFor="state">
          State:
          <select name="state" id="state" className="input" onChange={onChangeForInputs} value={formData.state}>
            <option value="" onChange={onChangeForInputs} />
            {usStates.map((state) => (
              <option value={state} onChange={onChangeForInputs}>{state}</option>
            ))}
          </select>
        </label>
        {errors.state && (
        <>
          <span className={styles.error}>{errors.state}</span>
        </>
        )}
        <br />
        <label htmlFor="postal">
          Postal Code (Zip Code):
          <input type="text" id="postal" name="postal" className="input" onChange={onChangeForInputs} value={formData.postal} />
        </label>
        {errors.postal && (
          <>
            <span className={styles.error}>{errors.postal}</span>
          </>
        )}
        <br />
        <label htmlFor="insuranceProvider">
          Insurance Provider:
          <input type="text" id="insuranceProvider" name="insuranceProvider" className="input" onChange={onChangeForInputs} value={formData.insuranceProvider} />
        </label>
        {errors.insuranceProvider && (
          <>
            <span className={styles.error}>{errors.insuranceProvider}</span>
          </>
        )}
        <br />
        <button type="submit" className="button">Edit Patient</button>
      </form>
    </div>
  );
};

export default EditPatientPage;

服务方法的代码

export const updatePatient = async (patient, setApiError) => {
  await HttpHelper(`/patients/${patient.id}`, 'PUT', patient)
    .then((response) => {
      if (response.status !== 201) {
        throw new Error(constants.API_ERROR);
      }
      return response.json();
    })
    .catch(() => {
      setApiError(true);
    });
};

export const getPatientById = async (
  patientID, setPatient, setFormData, setApiError
) => {
  await HttpHelper(`/patients/${patientID}`, 'GET')
    .then((response) => {
      if (response.status === 200) {
        return response.json();
      }
      throw new Error(constants.API_ERROR);
    })
    .then((body) => {
      setPatient(body);
      setFormData({
        firstName: body.firstName,
        lastName: body.lastName,
        age: body.age,
        insuranceProvider: body.insuranceProvider,
        email: body.email,
        height: body.height,
        weight: body.weight,
        ssn: body.ssn,
        street1: body.street1,
        street2: body.street2,
        city: body.city,
        state: body.state,
        postal: body.postal,
        gender: body.gender
      });
    })
    .catch(() => {
      setApiError(true);
    });
};
2个回答

即便如此,这也不是一个完整的答案:我认为错误发生在所示行下方(带有 <input /> 的行)。但我无法说出为什么 formData 此时是 undefined

Gregor
2022-01-02

我发现错误出在验证器中,而我在原始帖子中没有提供该验证器。

我忘记在验证后返回错误,因此如果将来有人遇到类似错误,请检查以确保在辅助方法中正确返回值。

这是验证器及其修复版本

const patientValidator = (patient) => {
  const postalPattern = /^\d{5}$|^\d{5}-\d{4}$/;
  const ssnPattern = /[0-9]{3}-[0-9]{2}-[0-9]{4}/;
  const namePattern = /^[a-zA-z.'-]{2,}$/;
  const emailPattern = /^[a-zA-z0-9]+@[a-zA-Z]+\.[a-zA-Z]+$/;
  sessionStorage.setItem('isValid', true);

  const errors = {
    firstName: '',
    lastName: '',
    age: '',
    insuranceProvider: '',
    email: '',
    height: '',
    weight: '',
    ssn: '',
    street1: '',
    street2: '',
    city: '',
    state: '',
    postal: '',
    gender: ''
  };

  if (patient.firstName === '') {
    errors.fName = 'The First Name field is required and can take all alphabetical characters and the following special characters .\'-';
    sessionStorage.setItem('isValid', false);
  } else if (!namePattern.test(patient.firstName)) {
    errors.fName = 'Input invalid the only characters allowed in this field are alphabetical characters and .-\'';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.lastName === '') {
    errors.fName = 'The Last Name field is required and can take all alphabetical characters and the following special characters .\'-';
    sessionStorage.setItem('isValid', false);
  } else if (!namePattern.test(patient.lastName)) {
    errors.fName = 'Input invalid the only characters allowed in this field are alphabetical characters and .-\'';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.postal === '') {
    errors.postal = 'The Postal Code field is required and can take either postal code format (E.G. 12345 or 12345-6789)';
    sessionStorage.setItem('isValid', false);
  } else if (!postalPattern.test(patient.postal)) {
    errors.postal = 'Input invalid the only characters allowed are numbers and a single hyphen in the following format (E.G. 12345 or 12345-6789)';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.email === '') {
    errors.email = 'The Email field is required and can take email addresses in the following format (E.G. [email protected])';
    sessionStorage.setItem('isValid', false);
  } else if (!emailPattern.test(patient.email)) {
    errors.email = 'Invalid input please ensure the email input is in the following format (E.G. [email protected])';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.age === '') {
    errors.age = 'The Age field is required and can only take in whole numbers';
    sessionStorage.setItem('isValid', false);
  } else if (!(/\d+/.test(patient.age))) {
    errors.age = 'The age field can only take whole numbers';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.street1 === '') {
    errors.street1 = 'The Street field is required';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.city === '') {
    errors.city = 'The City field is required and can only take in aphabetical characters';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.state === '') {
    errors.state = 'The State field is required please select one from the dropdown';
  }

  if (patient.height === '') {
    errors.height = 'The Height field is required and can only take in whole numbers';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.weight === '') {
    errors.weight = 'The Weight field is required and can only take in whole numbers';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.ssn === '') {
    errors.ssn = 'The Social Security Number field is required and should follow the format 123-45-6789';
    sessionStorage.setItem('isValid', false);
  } else if (!ssnPattern.test(patient.ssn)) {
    errors.ssn = 'Invalid input please ensure ssn input is in the following format 123-45-6789';
  }

  if (patient.insuranceProvider === '') {
    errors.insuranceProvider = 'The Insurance Provider field is required if the patient Uninsured or Self Insured enter that instead of leaving the field blank';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.gender === '') {
    errors.gender = 'The Gender field is required please select the one that best represents the patient from the dropdown';
    sessionStorage.setItem('isValid', false);
  }

}; export default patientValidator;
const patientValidator = (patient) => {
  const postalPattern = /^\d{5}$|^\d{5}-\d{4}$/;
  const ssnPattern = /[0-9]{3}-[0-9]{2}-[0-9]{4}/;
  const namePattern = /^[a-zA-z.'-]{2,}$/;
  const emailPattern = /^[a-zA-z0-9]+@[a-zA-Z]+\.[a-zA-Z]+$/;
  sessionStorage.setItem('isValid', true);

  const errors = {
    firstName: '',
    lastName: '',
    age: '',
    insuranceProvider: '',
    email: '',
    height: '',
    weight: '',
    ssn: '',
    street1: '',
    street2: '',
    city: '',
    state: '',
    postal: '',
    gender: ''
  };

  if (patient.firstName === '') {
    errors.fName = 'The First Name field is required and can take all alphabetical characters and the following special characters .\'-';
    sessionStorage.setItem('isValid', false);
  } else if (!namePattern.test(patient.firstName)) {
    errors.fName = 'Input invalid the only characters allowed in this field are alphabetical characters and .-\'';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.lastName === '') {
    errors.fName = 'The Last Name field is required and can take all alphabetical characters and the following special characters .\'-';
    sessionStorage.setItem('isValid', false);
  } else if (!namePattern.test(patient.lastName)) {
    errors.fName = 'Input invalid the only characters allowed in this field are alphabetical characters and .-\'';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.postal === '') {
    errors.postal = 'The Postal Code field is required and can take either postal code format (E.G. 12345 or 12345-6789)';
    sessionStorage.setItem('isValid', false);
  } else if (!postalPattern.test(patient.postal)) {
    errors.postal = 'Input invalid the only characters allowed are numbers and a single hyphen in the following format (E.G. 12345 or 12345-6789)';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.email === '') {
    errors.email = 'The Email field is required and can take email addresses in the following format (E.G. [email protected])';
    sessionStorage.setItem('isValid', false);
  } else if (!emailPattern.test(patient.email)) {
    errors.email = 'Invalid input please ensure the email input is in the following format (E.G. [email protected])';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.age === '') {
    errors.age = 'The Age field is required and can only take in whole numbers';
    sessionStorage.setItem('isValid', false);
  } else if (!(/\d+/.test(patient.age))) {
    errors.age = 'The age field can only take whole numbers';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.street1 === '') {
    errors.street1 = 'The Street field is required';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.city === '') {
    errors.city = 'The City field is required and can only take in aphabetical characters';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.state === '') {
    errors.state = 'The State field is required please select one from the dropdown';
  }

  if (patient.height === '') {
    errors.height = 'The Height field is required and can only take in whole numbers';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.weight === '') {
    errors.weight = 'The Weight field is required and can only take in whole numbers';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.ssn === '') {
    errors.ssn = 'The Social Security Number field is required and should follow the format 123-45-6789';
    sessionStorage.setItem('isValid', false);
  } else if (!ssnPattern.test(patient.ssn)) {
    errors.ssn = 'Invalid input please ensure ssn input is in the following format 123-45-6789';
  }

  if (patient.insuranceProvider === '') {
    errors.insuranceProvider = 'The Insurance Provider field is required if the patient Uninsured or Self Insured enter that instead of leaving the field blank';
    sessionStorage.setItem('isValid', false);
  }

  if (patient.gender === '') {
    errors.gender = 'The Gender field is required please select the one that best represents the patient from the dropdown';
    sessionStorage.setItem('isValid', false);
  }

  return errors;
}; export default patientValidator;

如您所见,我的验证器只是缺少返回语句。感谢 Gregor 指出浏览器显示的错误不是针对它所说的行,这导致我检查了错误范围。

Kris Bell
2022-01-02