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