我在从输入中更新嵌套对象的状态时遇到问题。
已更新更多代码。我正在尝试建立一个多步骤表单。第一页获取团队信息,第二页获取玩家信息。
父组件:
export class MainForm extends Component {
state = {
step: 1,
teamName: '',
teamManagerName: '',
teamManagerEmail: '',
player: [{
firstName: '',
lastName: '',
email: '',
height: ''
}]
}
// proceed to next step
nextStep = () => {
const { step } = this.state;
this.setState({
step: step + 1
})
}
// go to previous step
prevStep = () => {
const { step } = this.state;
this.setState({
step: step - 1
})
}
// handle fields change
handleChange = input => e => {
this.setState({[input]: e.target.value});
}
render() {
const { step } = this.state;
const { teamName, teamManagerName, teamManagerEmail, player: { firstName, lastName, email, height}} = this.state;
const values = {teamName, teamManagerName, teamManagerEmail, player: { firstName, lastName, email, height}};
switch(step) {
case 1:
return (
<FormTeamDetails
nextStep={this.nextStep}
handleChange={this.handleChange}
values={values}
/>
)
case 2:
return (
<FormPlayerDetails
nextStep={this.nextStep}
prevStep={this.prevStep}
handleChange={this.handleChange}
values={values}
/>
)
case 3:
return (
<Confirm
nextStep={this.nextStep}
prevStep={this.prevStep}
values={values}
/>
)
case 4:
return (
<h1>Scuccess!</h1>
)
}
}
}
下一个代码段是表单的第一页和子组件之一。 handleChange函数在这里成功完成其工作。
export class FormTeamDetails extends Component {
continue = e => {
e.preventDefault();
this.props.nextStep();
}
render() {
const { values, handleChange } = this.props;
console.log(this.props)
return (
<Container>
<Form>
<FormGroup>
<Label for="teamName">Team Name</Label>
<Input
type="teamName"
name="teamName"
onChange={handleChange('teamName')}
defaultValue={values.teamName} />
<Label for="teamManagerName">Team Manager Name</Label>
<Input
type="teamManagerName"
name="teamManagerName"
onChange={handleChange('teamManagerName')}
defaultValue={values.teamManagerName}
/>
<Label for="teamManagerEmail">Team Manager Email</Label>
<Input
type="teamManagerEmail"
name="teamManagerEmail"
onChange={handleChange('teamManagerEmail')}
defaultValue={values.teamManagerEmail} />
<Button
label="Next"
// primary="true"
onClick={this.continue}
style={{float: 'right'}}>Next</Button>
</FormGroup>
</Form>
</Container>
)
}
}
这是表单的第二页,也是我遇到的问题:
export class FormPlayerDetails extends Component {
continue = e => {
e.preventDefault();
this.props.nextStep();
}
back = e => {
e.preventDefault();
this.props.prevStep();
}
render() {
const { values: { player }, handleChange, values } = this.props;
return (
<Container>
<h3>Add players</h3>
<Form>
<Row form>
<Col md={3}>
<FormGroup>
<Input type="firstName"
name="firstName"
id="firstName"
placeholder="First Name"
defaultValue={values.player.firstName}
onChange={handleChange('values.player.firstName')}
/>
</FormGroup>
</Col>
<Col md={3}>
<FormGroup>
<Input type="lastName" name="lastName" id="lastName" placeholder="Last Name" />
</FormGroup>
</Col>
<Col md={3}>
<FormGroup>
<Input type="email" name="email" id="email" placeholder="Email" />
</FormGroup>
</Col>
</Row>
<Row form>
<Col>
<Button
label="Back"
// primary="true"
onClick={this.back}
style={{float: 'left'}}>Back</Button>
</Col>
<Col>
<Button
label="Next"
// primary="true"
onClick={this.continue}
style={{float: 'right'}}>Next</Button>
</Col>
</Row>
</Form>
</Container>
)
}
}
我无法使用输入值更新播放器属性。另外,我想在此组件中添加多个玩家输入字段。我希望至少要有5名玩家添加到团队中,因此要在父组件中添加玩家数组。请让我知道是否应该以其他方式处理此问题。预先谢谢你!
答案 0 :(得分:1)
您处于状态的player
属性是一个数组,但是您将其视为对象。因此,我假设将有一个玩家,它将是一个对象。这是您的情况的一种解决方案。但是,由于您已经为输入设置了name
属性,因此感觉好像您正在处理许多不必要的事情,如传递值等。我不知道,也许您正在考虑其他情况。
这是handleChange
部分:
handleChange = input => e => {
const { target } = e;
if (input === "player") {
this.setState(prev => ({
player: {
...prev.player,
[target.name]: target.value
}
}));
} else {
this.setState({ [input]: target.value });
}
};
这是输入部分:
<Input
type="firstName"
name="firstName"
id="firstName"
placeholder="First Name"
defaultValue={values.player.firstName}
onChange={handleChange("player")}
/>
如您所见,我正在传递handleChange
和player
属性,并从您的输入中获取name
。然后,在handleChange
方法中,使用功能状态和传播语法,我正在更新player
。
class App extends React.Component {
state = {
step: 1,
teamName: "",
player: {
firstName: "",
lastName: "",
email: ""
}
};
handleChange = input => e => {
const { target } = e;
if (input === "player") {
this.setState(prev => ({
player: {
...prev.player,
[target.name]: target.value
}
}));
} else {
this.setState({ [input]: target.value });
}
};
render() {
return (
<div>
<Input handleChange={this.handleChange} />
<div>{JSON.stringify(this.state)}</div>
</div>
);
}
}
class Input extends React.Component {
render() {
const { handleChange } = this.props;
return (
<div>
<div>
<span>firstName</span>
<input
type="firstName"
name="firstName"
id="firstName"
onChange={handleChange("player")}
/>
</div>
<div>
<span>team</span>
<input
type="teamName"
name="teamName"
onChange={handleChange("teamName")}
/>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" />
此处是players
的更新版本,为数组(请注意复数名称)。因此,在这个简单的版本中,我们保留了一个players
数组,上面有一些唯一的id
。这就是我们要锁定更新后的播放器的方式。检查每个input
,现在有一个id
,我们将其设置为player
的那个。在handleChange
函数中,这次我们正在映射players
(因此将返回一个新数组),然后如果id
与我们的玩家的匹配,我们将更新其相关属性。如果id
不匹配,我们将不做任何事情返回原始的player
。
handleChange
部分是您需要重点关注的部分。我们正在使用player
组件中每个Input
的属性来映射和呈现输入。这似乎有点令人困惑,但是如果您深入研究它,便可以理解。我们正在使用Object.entries
来映射属性,但是在此之前,我们正在清理id
,因为我们不想显示它。
您可以在下面找到有效的代码段。
class App extends React.Component {
state = {
step: 1,
teamName: "",
players: [
{
id: 1,
firstName: "foo",
lastName: "foo's lastname",
email: "foo@foo.com"
},
{
id: 2,
firstName: "bar",
lastName: "bar's lastname",
email: "bar@bar.com"
}
]
};
handleChange = input => e => {
const { target } = e;
if (input === "players") {
this.setState({
players: this.state.players.map(player => {
if (player.id === Number(target.id)) {
return { ...player, [target.name]: target.value };
}
return player;
})
});
} else {
this.setState({ [input]: target.value });
}
};
render() {
return (
<div>
<Input handleChange={this.handleChange} players={this.state.players} />
<div>
{this.state.players.map(player => (
<div>
<h3>Player {player.id}</h3>
<div>First Name: {player.firstName}</div>
<div>Last Name: {player.lastName}</div>
<div>Email: {player.email}</div>
</div>
))}
</div>
</div>
);
}
}
class Input extends React.Component {
render() {
const { handleChange, players } = this.props;
return (
<div>
{players.map(player => {
const { id, ...playerWithoutId } = player;
return (
<div key={player.id}>
<h3>Player {player.id}</h3>
{Object.entries(playerWithoutId).map(([key, value]) => (
<div>
<span>{key}</span>
<input
name={key}
id={player.id}
onChange={handleChange("players")}
defaultValue={value}
/>
</div>
))}
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" />
答案 1 :(得分:0)
对于FormPlayerDetails,您不需要传递完整的值,而只需要传递values.players。而且由于您的玩家属性是一个表格,所以请改用map函数