我目前正在构建一个简单的注册表单页面,以增强对React Web Apps的了解。我有许多不同类型的表单元素。当我使用自定义钩子来处理不是简单文本字段的任何表单字段中的更改时,我遇到以下错误。
TypeError:无法读取未定义的属性“名称” (匿名功能) C:/用户/巴黎/桌面/covidsocial/frontend/src/libs/hooksLib.js:11 函数(事件){
9 | setValues({
10 | ...fields,
> 11 | [event.target.name]: event.target.value
| ^ 12 | });
13 | }
14 | ];
只要我从区域和国家选择器下拉列表或日期选择器中选择一个国家,就会出现上述错误消息。我尝试使用name和control-id元素作为id,但是仍然收到与上面相同的错误消息。我认为问题在于我如何设定自己的价值观,但是我对React还是很陌生,很难确定到底发生了什么。任何帮助将不胜感激! 这是我的Signup.js类的相关代码以及自定义的react hook
hookslib.js
import { useState } from "react";
export function useFormFields(initialState) {
const [fields, setValues] = useState(initialState);
return [
fields,
function(event) {
setValues({
...fields,
[event.target.name]: event.target.value
});
}
];
}
Signup.js
export default function Signup() {
const [fields, handleFieldChange] = useFormFields({
email: "",
password: "",
confirmPassword: "",
confirmationCode: "",
gender: "",
onList: false,
dateOfBirth: "",
mailingAddressLine1: "",
mailingAddressLine2: "",
mailingAddressCity: "",
mailingAddressState: "",
mailingAddressZip: "",
billingAddressLine1: "",
billingAddressLine2: "",
billingAddressCity: "",
billingAddressState: "",
billingAddressZip: "",
useShippingAsBilling: false,
});
const history = useHistory();
const [newUser, setNewUser] = useState(null);
const { userHasAuthenticated } = useAppContext();
const [isLoading, setIsLoading] = useState(false);
function validateForm() {
return (
fields.email.length > 0 &&
fields.password.length > 0 &&
fields.password === fields.confirmPassword
);
}
function validateConfirmationForm() {
return fields.confirmationCode.length > 0;
}
async function handleSubmit(event) {
event.preventDefault();
setIsLoading(true);
try {
const newUser = await Auth.signUp({
username: fields.email,
password: fields.password,
confirmPassword: fields.confirmPassword,
gender: fields.gender,
firstName: fields.firstName,
lastName: fields.lastName,
onList: fields.onList,
dateOfBirth: fields.dateOfBirth,
mailingAddressLine1: fields.mailingAddressLine1,
mailingAddressLine2: fields.mailingAddressLine2,
mailingAddressCity: fields.mailingAddressCity,
mailingAddressState: fields.mailingAddressState,
mailingAddressZip: fields.mailingAddressZip,
mailingAddressCountry: fields.mailingAddressCountry,
billingAddressCountry: fields.billingAddressCountry,
billingAddressLine1: fields.billingAddressLine1,
billingAddressLine2: fields.billingAddressLine2,
billingAddressCity: fields.billingAddressCity,
billingAddressState: fields.billingAddressState,
billingAddressZip: fields.billingAddressZip,
});
setIsLoading(false);
setNewUser(newUser);
} catch (e) {
onError(e);
setIsLoading(false);
}
}
async function handleConfirmationSubmit(event) {
event.preventDefault();
setIsLoading(true);
try {
await Auth.confirmSignUp(fields.email, fields.confirmationCode);
await Auth.signIn(fields.email, fields.password);
userHasAuthenticated(true);
history.push("/");
} catch (e) {
onError(e);
setIsLoading(false);
}
}
function renderConfirmationForm() {
return (
<form onSubmit={handleConfirmationSubmit}>
<FormGroup controlId="confirmationCode" bsSize="large">
<ControlLabel>Confirmation Code</ControlLabel>
<FormControl
autoFocus
type="tel"
onChange={handleFieldChange}
value={fields.confirmationCode}
/>
<HelpBlock>Please check your email for the code.</HelpBlock>
</FormGroup>
<LoaderButton
block
type="submit"
bsSize="large"
isLoading={isLoading}
disabled={!validateConfirmationForm()}
>
Verify
</LoaderButton>
</form>
);
}
function renderForm() {
return (
<form onSubmit={handleSubmit}>
<FormGroup controlId="email" bsSize="large">
<ControlLabel>Email</ControlLabel>
<FormControl
autoFocus
name = "email"
type="email"
value={fields.email}
onChange={handleFieldChange}
/>
</FormGroup>
<FormGroup controlId="password" bsSize="large">
<ControlLabel>Password</ControlLabel>
<FormControl
type="password"
name = "password"
value={fields.password}
onChange={handleFieldChange}
/>
</FormGroup>
<FormGroup controlId="confirmPassword" bsSize="large">
<ControlLabel>Confirm Password</ControlLabel>
<FormControl
type="password"
name = "confirmPassword"
onChange={handleFieldChange}
value={fields.confirmPassword}
/>
</FormGroup>
<FormGroup controlId="mailingAddressLine1" bsSize="large">
<ControlLabel>Mailing Address Line 1</ControlLabel>
<FormControl
type="text"
name = "mailingAddressLine1"
onChange={handleFieldChange}
value={fields.mailingAddressLine1}
/>
</FormGroup>
<FormGroup controlId="mailingAddressLine2" bsSize="large">
<ControlLabel>Mailing Address Line 2</ControlLabel>
<FormControl
type="text"
name = "mailingAddressLine2"
onChange={handleFieldChange}
value={fields.mailingAddressLine2}
/>
</FormGroup>
<FormGroup controlId="mailingAddressCountry" bsSize="large">
<ControlLabel>Country</ControlLabel>
<CountryDropdown
name = "mailingAddressCountry"
country={fields.mailingAddressCountry}
value={fields.mailingAddressCountry}
onChange={handleFieldChange} />
</FormGroup>
<FormGroup controlId="mailingAddressRegion" bsSize="large">
<ControlLabel>State</ControlLabel>
<RegionDropdown
//country={country}
name="mailingAddressRegion"
country={fields.mailingAddressCountry}
value={fields.mailingAddressState}
onChange={handleFieldChange} />
</FormGroup>
<FormGroup controlId="city" bsSize="large">
<ControlLabel>City</ControlLabel>
<FormControl
type="text"
name="city"
onChange={handleFieldChange}
value={fields.mailingAddressCity}
/>
</FormGroup>
<FormGroup controlId="zipCode" bsSize="large">
<ControlLabel>Zip Code</ControlLabel>
<FormControl
type="text"
name="zipCode"
onChange={handleFieldChange}
value={fields.mailingAddressZip}
/>
</FormGroup>
<FormGroup controlId="useShippingAsBilling" bsSize="large">
<label>
Use Shipping As Billing:
<input
name = "useShippingAsBilling"
type="checkbox"
id="useShippingasBilling"
value={fields.useShippingAsBilling}
checked={fields.useShippingAsBilling === true}
onChange={handleFieldChange} />
</label>
</FormGroup>
<br />
<FormGroup controlId="billingAddressLine1" bsSize="large">
<ControlLabel>Billing Address Line 1</ControlLabel>
<FormControl
name ="billingAddressLine1"
type="text"
value={fields.billingAddressLine1}
onChange={handleFieldChange}
/>
</FormGroup>
<FormGroup controlId="billingAddressLine2" bsSize="large">
<ControlLabel>Billing Address Line 2</ControlLabel>
<FormControl
name ="billingAddressLine2"
type="text"
value={fields.billingAddressLine2}
onChange={handleFieldChange}
/>
</FormGroup>
<FormGroup controlId="billingAddressCountry" bsSize="large">
<ControlLabel>BillingAddressCountry</ControlLabel>
<CountryDropdown
name="billingAddressCountry"
value={fields.billingAddressCountry}
onChange={handleFieldChange}
/>
</FormGroup>
<FormGroup controlId="mailingAddressRegion" bsSize="large">
<ControlLabel>Billing Address Region</ControlLabel>
<RegionDropdown
name="mailingAddressRegion"
country={fields.billingAddressCountry}
value={fields.billingAddressRegion}
onChange={handleFieldChange} />
</FormGroup>
<FormGroup controlId="billingCity" bsSize="large">
<ControlLabel>City</ControlLabel>
<FormControl
name = "billingCity"
type="text"
value={fields.billingAddressCity}
onChange={handleFieldChange}
/>
</FormGroup>
<FormGroup controlId="billingZipCode" bsSize="large">
<ControlLabel>Zip Code</ControlLabel>
<FormControl
name = "billingZipCode"
type="text"
value={fields.billingAddressZip}
onChange={handleFieldChange}
/>
</FormGroup>
<FormGroup controlId="gender" bsSize="sm">
<ControlLabel>Gender</ControlLabel>
<br></br>
<ControlLabel>Male</ControlLabel>
<FormControl
name = "gender"
type="radio"
onChange={handleFieldChange}
value={fields.gender}
checked={fields.gender === 'male'}
/>
<ControlLabel>Female</ControlLabel>
<FormControl
name = "gender"
type="radio"
onChange={handleFieldChange}
value={fields.gender}
checked={fields.gender === 'female'}
/>
<ControlLabel>Other</ControlLabel>
<FormControl
name = "gender"
type="radio"
onChange={handleFieldChange}
value={fields.gender}
checked={fields.gender === 'other'}
/>
</FormGroup>
<FormGroup controlId="onList" bsSize="sm">
<br></br>
<ControlLabel>Join Email List</ControlLabel>
<br></br>
<ControlLabel>Yes</ControlLabel>
<FormControl
name = "onList"
type="checkbox"
onChange={handleFieldChange}
value={fields.onList}
checked={fields.onList === 'true'}
/>
</FormGroup>
<FormGroup controlId="dateOfBirth">
<ControlLabel>Date of Birth</ControlLabel>
<DatePicker
name="dateOfBirth"
value={fields.dateofBirth}
selected={fields.dateOfBirth}
onChange={handleFieldChange}
locale="en"
/>
</FormGroup>
<FormGroup controlId="content">
<ControlLabel>Notes Area</ControlLabel>
<FormControl
name = "content"
value={fields.content}
componentClass="textarea"
onChange={handleFieldChange}
/>
</FormGroup>
<LoaderButton
block
type="submit"
bsSize="large"
isLoading={isLoading}
disabled={!validateForm()}
>
Signup
</LoaderButton>
</form>
);
}
return (
<div className="Signup">
{newUser === null ? renderForm() : renderConfirmationForm()}
</div>
);
}
答案 0 :(得分:1)
这是处理变更事件和保持状态值的一种聪明方法。但是,您确实对此组件库抱有很大的信心,以便与HTML对应组件一致地触发onChange事件。
我在docs中注意到,onChange与您可能期望的有点不同:
<CountryDropdown
value={country}
onChange={(val) => this.selectCountry(val)} />
<RegionDropdown
country={country}
value={region}
onChange={(val) => this.selectRegion(val)} />
这两种方法都希望箭头函数处理程序接收val属性,因此您可以考虑重写实现:
<CountryDropdown
name = "mailingAddressCountry"
country={fields.mailingAddressCountry}
value={fields.mailingAddressCountry}
onChange={(val) => updateField({ mailingAddress: val})} />
并修改您的钩子,以免您从裸事件开始工作。它需要更多的语法,并且可能有一种更简洁的方法,但是它将为您提供处理边缘情况所需的控制。像这样:
import { useState } from "react";
export function useFormFields(initialState) {
const [fields, setValues] = useState(initialState);
return [
fields,
function(value) {
setValues({
...fields,
...value
});
}
];
}